blob: 1005ebc30cc3d16fc59724989bce02dbc892ac06 [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
Anton Staafe517a4f2011-03-14 12:28:06 -070064*parse_field_value(build_image_context *context,
Peer Chen7557d9b2011-02-24 09:29:23 -080065 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
Anton Staafe517a4f2011-03-14 12:28:06 -070088enum_item s_devtype_table[] =
Peer Chen7557d9b2011-02-24 09:29:23 -080089{
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
Anton Staafe517a4f2011-03-14 12:28:06 -0700100enum_item s_sdmmc_data_width_table[] =
Peer Chen7557d9b2011-02-24 09:29:23 -0800101{
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
Anton Staafe517a4f2011-03-14 12:28:06 -0700115enum_item s_spi_clock_source_table[] =
Peer Chen7557d9b2011-02-24 09:29:23 -0800116{
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
Anton Staafe517a4f2011-03-14 12:28:06 -0700148enum_item s_nvboot_memory_type_table[] =
Peer Chen3a834ed2011-03-04 09:30:05 -0800149{
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
Anton Staafe517a4f2011-03-14 12:28:06 -0700165#define TOKEN(name) \
166 token_##name, nvbct_lib_id_sdram_##name, field_type_u32, NULL
Peer Chen3a834ed2011-03-04 09:30:05 -0800167
Anton Staafe517a4f2011-03-14 12:28:06 -0700168field_item s_sdram_field_table[] =
169{
170 { "MemoryType", token_memory_type, nvbct_lib_id_sdram_memory_type,
171 field_type_enum, s_nvboot_memory_type_table },
172
173 { "PllMChargePumpSetupControl", TOKEN(pllm_charge_pump_setup_ctrl) },
174 { "PllMLoopFilterSetupControl", TOKEN(pllm_loop_filter_setup_ctrl) },
175 { "PllMInputDivider", TOKEN(pllm_input_divider) },
176 { "PllMFeedbackDivider", TOKEN(pllm_feedback_divider) },
177 { "PllMPostDivider", TOKEN(pllm_post_divider) },
178 { "PllMStableTime", TOKEN(pllm_stable_time) },
179 { "EmcClockDivider", TOKEN(emc_clock_divider) },
180 { "EmcAutoCalInterval", TOKEN(emc_auto_cal_interval) },
181 { "EmcAutoCalConfig", TOKEN(emc_auto_cal_config) },
182 { "EmcAutoCalWait", TOKEN(emc_auto_cal_wait) },
183 { "EmcPinProgramWait", TOKEN(emc_pin_program_wait) },
184 { "EmcRc", TOKEN(emc_rc) },
185 { "EmcRfc", TOKEN(emc_rfc) },
186 { "EmcRas", TOKEN(emc_ras) },
187 { "EmcRp", TOKEN(emc_rp) },
188 { "EmcR2w", TOKEN(emc_r2w) },
189 { "EmcW2r", TOKEN(emc_w2r) },
190 { "EmcR2p", TOKEN(emc_r2p) },
191 { "EmcW2p", TOKEN(emc_w2p) },
192 { "EmcRrd", TOKEN(emc_rrd) },
193 { "EmcRdRcd", TOKEN(emc_rd_rcd) },
194 { "EmcWrRcd", TOKEN(emc_wr_rcd) },
195 { "EmcRext", TOKEN(emc_rext) },
196 { "EmcWdv", TOKEN(emc_wdv) },
197 { "EmcQUseExtra", TOKEN(emc_quse_extra) },
198 { "EmcQUse", TOKEN(emc_quse) },
199 { "EmcQRst", TOKEN(emc_qrst) },
200 { "EmcQSafe", TOKEN(emc_qsafe) },
201 { "EmcRdv", TOKEN(emc_rdv) },
202 { "EmcRefresh", TOKEN(emc_refresh) },
203 { "EmcBurstRefreshNum", TOKEN(emc_burst_refresh_num) },
204 { "EmcPdEx2Wr", TOKEN(emc_pdex2wr) },
205 { "EmcPdEx2Rd", TOKEN(emc_pdex2rd) },
206 { "EmcPChg2Pden", TOKEN(emc_pchg2pden) },
207 { "EmcAct2Pden", TOKEN(emc_act2pden) },
208 { "EmcAr2Pden", TOKEN(emc_ar2pden) },
209 { "EmcRw2Pden", TOKEN(emc_rw2pden) },
210 { "EmcTxsr", TOKEN(emc_txsr) },
211 { "EmcTcke", TOKEN(emc_tcke) },
212 { "EmcTfaw", TOKEN(emc_tfaw) },
213 { "EmcTrpab", TOKEN(emc_trpab) },
214 { "EmcTClkStable", TOKEN(emc_tclkstable) },
215 { "EmcTClkStop", TOKEN(emc_tclkstop) },
216 { "EmcTRefBw", TOKEN(emc_trefbw) },
217 { "EmcFbioCfg1", TOKEN(emc_fbio_cfg1) },
218 { "EmcFbioDqsibDlyMsb", TOKEN(emc_fbio_dqsib_dly_msb) },
219 { "EmcFbioDqsibDly", TOKEN(emc_fbio_dqsib_dly) },
220 { "EmcFbioQuseDlyMsb", TOKEN(emc_fbio_quse_dly_msb) },
221 { "EmcFbioQuseDly", TOKEN(emc_fbio_quse_dly) },
222 { "EmcFbioCfg5", TOKEN(emc_fbio_cfg5) },
223 { "EmcFbioCfg6", TOKEN(emc_fbio_cfg6) },
224 { "EmcFbioSpare", TOKEN(emc_fbio_spare) },
225 { "EmcMrsResetDllWait", TOKEN(emc_mrs_reset_dll_wait) },
226 { "EmcMrsResetDll", TOKEN(emc_mrs_reset_dll) },
227 { "EmcMrsDdr2DllReset", TOKEN(emc_mrs_ddr2_dll_reset) },
228 { "EmcMrs", TOKEN(emc_mrs) },
229 { "EmcEmrsEmr2", TOKEN(emc_emrs_emr2) },
230 { "EmcEmrsEmr3", TOKEN(emc_emrs_emr3) },
231 { "EmcEmrsDdr2DllEnable", TOKEN(emc_emrs_ddr2_dll_enable) },
232 { "EmcEmrsDdr2OcdCalib", TOKEN(emc_emrs_ddr2_ocd_calib) },
233 { "EmcEmrs", TOKEN(emc_emrs) },
234 { "EmcMrw1", TOKEN(emc_mrw1) },
235 { "EmcMrw2", TOKEN(emc_mrw2) },
236 { "EmcMrw3", TOKEN(emc_mrw3) },
237 { "EmcMrwResetCommand", TOKEN(emc_mrw_reset_command) },
238 { "EmcMrwResetNInitWait", TOKEN(emc_mrw_reset_ninit_wait) },
239 { "EmcAdrCfg1", TOKEN(emc_adr_cfg1) },
240 { "EmcAdrCfg", TOKEN(emc_adr_cfg) },
241 { "McEmemCfg", TOKEN(mc_emem_Cfg) },
242 { "McLowLatencyConfig", TOKEN(mc_lowlatency_config) },
243 { "EmcCfg2", TOKEN(emc_cfg2) },
244 { "EmcCfgDigDll", TOKEN(emc_cfg_dig_dll) },
245 { "EmcCfgClktrim0", TOKEN(emc_cfg_clktrim0) },
246 { "EmcCfgClktrim1", TOKEN(emc_cfg_clktrim1) },
247 { "EmcCfgClktrim2", TOKEN(emc_cfg_clktrim2) },
248 { "EmcCfg", TOKEN(emc_cfg) },
249 { "EmcDbg", TOKEN(emc_dbg) },
250 { "AhbArbitrationXbarCtrl", TOKEN(ahb_arbitration_xbar_ctrl) },
251 { "EmcDllXformDqs", TOKEN(emc_dll_xform_dqs) },
252 { "EmcDllXformQUse", TOKEN(emc_dll_xform_quse) },
253 { "WarmBootWait", TOKEN(warm_boot_wait) },
254 { "EmcCttTermCtrl", TOKEN(emc_ctt_term_ctrl) },
255 { "EmcOdtWrite", TOKEN(emc_odt_write) },
256 { "EmcOdtRead", TOKEN(emc_odt_read) },
257 { "EmcZcalRefCnt", TOKEN(emc_zcal_ref_cnt) },
258 { "EmcZcalWaitCnt", TOKEN(emc_zcal_wait_cnt) },
259 { "EmcZcalMrwCmd", TOKEN(emc_zcal_mrw_cmd) },
260 { "EmcMrwZqInitDev0", TOKEN(emc_mrw_zq_init_dev0) },
261 { "EmcMrwZqInitDev1", TOKEN(emc_mrw_zq_init_dev1) },
262 { "EmcMrwZqInitWait", TOKEN(emc_mrw_zq_init_wait) },
263 { "EmcDdr2Wait", TOKEN(emc_ddr2_wait) },
264 { "PmcDdrPwr", TOKEN(pmc_ddr_pwr) },
265 { "ApbMiscGpXm2CfgAPadCtrl", TOKEN(apb_misc_gp_xm2cfga_pad_ctrl) },
266 { "ApbMiscGpXm2CfgCPadCtrl2", TOKEN(apb_misc_gp_xm2cfgc_pad_ctrl2) },
267 { "ApbMiscGpXm2CfgCPadCtrl", TOKEN(apb_misc_gp_xm2cfgc_pad_ctrl) },
268 { "ApbMiscGpXm2CfgDPadCtrl2", TOKEN(apb_misc_gp_xm2cfgd_pad_ctrl2) },
269 { "ApbMiscGpXm2CfgDPadCtrl", TOKEN(apb_misc_gp_xm2cfgd_pad_ctrl) },
270 { "ApbMiscGpXm2ClkCfgPadCtrl", TOKEN(apb_misc_gp_xm2clkcfg_Pad_ctrl)},
271 { "ApbMiscGpXm2CompPadCtrl", TOKEN(apb_misc_gp_xm2comp_pad_ctrl) },
272 { "ApbMiscGpXm2VttGenPadCtrl", TOKEN(apb_misc_gp_xm2vttgen_pad_ctrl)},
273 { NULL, 0, 0, 0, NULL }
Peer Chen3a834ed2011-03-04 09:30:05 -0800274};
275
Anton Staafe517a4f2011-03-14 12:28:06 -0700276#undef TOKEN
277#define TOKEN(name) \
278 token_##name, nvbct_lib_id_nand_##name, field_type_u32, NULL
279
280field_item s_nand_table[] =
Peer Chen053d5782011-03-03 10:12:58 -0800281{
Anton Staafe517a4f2011-03-14 12:28:06 -0700282 { "ClockDivider", TOKEN(clock_divider) },
Peer Chen053d5782011-03-03 10:12:58 -0800283 /* Note: NandTiming2 must appear before NandTiming, because NandTiming
284 * is a prefix of NandTiming2 and would otherwise match first.
285 */
Anton Staafe517a4f2011-03-14 12:28:06 -0700286 { "NandTiming2", TOKEN(nand_timing2) },
287 { "NandTiming", TOKEN(nand_timing) },
288 { "BlockSizeLog2", TOKEN(block_size_log2) },
289 { "PageSizeLog2", TOKEN(page_size_log2) },
290 { NULL, 0, 0, 0, NULL }
Peer Chen053d5782011-03-03 10:12:58 -0800291};
292
Anton Staafe517a4f2011-03-14 12:28:06 -0700293#undef TOKEN
294#define TOKEN(name) \
295 token_##name, nvbct_lib_id_sdmmc_##name, field_type_u32, NULL
Peer Chen7557d9b2011-02-24 09:29:23 -0800296
Anton Staafe517a4f2011-03-14 12:28:06 -0700297field_item s_sdmmc_table[] =
298{
299 { "ClockDivider", TOKEN(clock_divider) },
300 { "DataWidth",
301 token_data_width,
302 nvbct_lib_id_sdmmc_data_width,
303 field_type_enum,
304 s_sdmmc_data_width_table },
305 { "MaxPowerClassSupported", TOKEN(max_power_class_supported) },
306 { NULL, 0, 0, 0, NULL }
Peer Chen7557d9b2011-02-24 09:29:23 -0800307};
308
Anton Staafe517a4f2011-03-14 12:28:06 -0700309#undef TOKEN
310#define TOKEN(name) \
311 token_##name, nvbct_lib_id_spiflash_##name, field_type_u8, NULL
Peer Chen7557d9b2011-02-24 09:29:23 -0800312
Anton Staafe517a4f2011-03-14 12:28:06 -0700313field_item s_spiflash_table[] =
314{
315 { "ReadCommandTypeFast", TOKEN(read_command_type_fast) },
316 { "ClockDivider", TOKEN(clock_divider) },
317 { "ClockSource",
318 token_clock_source,
319 nvbct_lib_id_spiflash_clock_source,
320 field_type_enum,
321 s_spi_clock_source_table },
322 { NULL, 0, 0, 0, NULL }
Peer Chen7557d9b2011-02-24 09:29:23 -0800323};
324
325static parse_subfield_item s_device_type_table[] =
326{
Peer Chen053d5782011-03-03 10:12:58 -0800327 { "NandParams.", token_nand_params,
328 s_nand_table, set_nand_param },
Peer Chen7557d9b2011-02-24 09:29:23 -0800329 { "SdmmcParams.", token_sdmmc_params,
330 s_sdmmc_table, set_sdmmc_param },
331 { "SpiFlashParams.", token_spiflash_params,
332 s_spiflash_table, set_spiflash_param },
333
334 { NULL, 0, NULL }
335};
336
Peer Chen8d782ee2011-01-18 21:34:18 -0500337static parse_item s_top_level_items[] =
338{
Peer Chen053d5782011-03-03 10:12:58 -0800339 { "Bctfile=", token_bct_file, parse_bct_file },
340 { "Attribute=", token_attribute, parse_value_u32 },
341 { "Attribute[", token_attribute, parse_array },
342 { "PageSize=", token_page_size, parse_value_u32 },
343 { "BlockSize=", token_block_size, parse_value_u32 },
344 { "PartitionSize=", token_partition_size, parse_value_u32 },
345 { "DevType[", token_dev_type, parse_array },
346 { "DeviceParam[", token_dev_param, parse_dev_param },
Peer Chen3a834ed2011-03-04 09:30:05 -0800347 { "SDRAM[", token_sdram, parse_sdram_param },
Peer Chen053d5782011-03-03 10:12:58 -0800348 { "BootLoader=", token_bootloader, parse_bootloader },
349 { "Redundancy=", token_redundancy, parse_value_u32 },
350 { "Version=", token_version, parse_value_u32 },
351 { "AddOn[", token_addon, parse_addon },
Peer Chen8d782ee2011-01-18 21:34:18 -0500352 { NULL, 0, NULL } /* Must be last */
353};
354
355/* Macro to simplify parser code a bit. */
356#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
357
358/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
359/* Returns the address of the character after the parsed data. */
360static char *
361parse_u32(char *statement, u_int32_t *val)
362{
363 u_int32_t value = 0;
364
365 while (*statement=='0') {
366 statement++;
367 }
368
369 if (*statement=='x' || *statement=='X') {
370 statement++;
371 while (((*statement >= '0') && (*statement <= '9')) ||
372 ((*statement >= 'a') && (*statement <= 'f')) ||
373 ((*statement >= 'A') && (*statement <= 'F'))) {
374 value *= 16;
375 if ((*statement >= '0') && (*statement <= '9')) {
376 value += (*statement - '0');
377 } else if ((*statement >= 'A') &&
378 (*statement <= 'F')) {
379 value += ((*statement - 'A')+10);
380 } else {
381 value += ((*statement - 'a')+10);
382 }
383 statement++;
384 }
385 } else {
386 while (*statement >= '0' && *statement <= '9') {
387 value = value*10 + (*statement - '0');
388 statement++;
389 }
390 }
391 *val = value;
392 return statement;
393}
394
Peer Chen7557d9b2011-02-24 09:29:23 -0800395char *
396parse_u8(char *statement, u_int32_t *val)
397{
398 char *retval;
399
400 retval = parse_u32(statement, val);
401
402 if (*val > 0xff) {
403 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
404 printf(" Parsed value = %d. Remaining text = %s\n",
405 *val, retval);
406 }
407
408 return retval;
409}
410
411
Peer Chen8d782ee2011-01-18 21:34:18 -0500412/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
413/* Returns the address of the character after the parsed data. */
414static char *
415parse_filename(char *statement, char *name, int chars_remaining)
416{
417 while (((*statement >= '0') && (*statement <= '9')) ||
418 ((*statement >= 'a') && (*statement <= 'z')) ||
419 ((*statement >= 'A') && (*statement <= 'Z')) ||
420 (*statement == '\\') ||
421 (*statement == '/' ) ||
422 (*statement == '~' ) ||
423 (*statement == '_' ) ||
424 (*statement == '-' ) ||
425 (*statement == '+' ) ||
426 (*statement == ':' ) ||
427 (*statement == '.' )) {
428 /* Check if the filename buffer is out of space, preserving one
429 * character to null terminate the string.
430 */
431 chars_remaining--;
432
433 if (chars_remaining < 1)
434 return NULL;
435 *name++ = *statement++;
436 }
437
438 /* Null terminate the filename. */
439 *name = '\0';
440
441 return statement;
442}
443
Peer Chen7557d9b2011-02-24 09:29:23 -0800444static char
445*parse_field_name(char *rest, field_item *field_table, field_item **field)
446{
447 u_int32_t i;
448 u_int32_t field_name_len = 0;
449
450 assert(field_table != NULL);
451 assert(rest != NULL);
452 assert(field != NULL);
453
454 while(*(rest + field_name_len) != '=')
455 field_name_len++;
456
457 /* Parse the field name. */
458 for (i = 0; field_table[i].name != NULL; i++) {
459 if ((strlen(field_table[i].name) == field_name_len) &&
460 !strncmp(field_table[i].name,
461 rest,
462 field_name_len)) {
463
464 *field = &(field_table[i]);
465 rest = rest + field_name_len;
466 return rest;
467 }
468 }
469
470 /* Field wasn't found or a parse error occurred. */
471 return NULL;
472}
473
474static char
475*parse_field_value(build_image_context *context,
476 char *rest,
477 field_item *field,
478 u_int32_t *value)
479{
480 assert(rest != NULL);
481 assert(field != NULL);
482 assert((field->type != field_type_enum)
483 || (field->enum_table != NULL));
484
485 switch (field->type) {
486 case field_type_enum:
487 rest = parse_enum(context, rest, field->enum_table, value);
488 break;
489
490 case field_type_u32:
491 rest = parse_u32(rest, value);
492 break;
493
494 case field_type_u8:
495 rest = parse_u8(rest, value);
496 break;
497
498 default:
499 printf("Unexpected field type %d at line %d\n",
500 field->type, __LINE__);
501 rest = NULL;
502 break;
503 }
504
505 return rest;
506}
507
508static char *
509parse_enum(build_image_context *context,
510 char *statement,
511 enum_item *table,
512 u_int32_t *val)
513{
514 int i;
515 char *rest;
516 int e;
517
518 for (i = 0; table[i].name != NULL; i++) {
519 if (!strncmp(table[i].name, statement,
520 strlen(table[i].name))) {
521 /* Lookup the correct value for the token. */
522 e = context->bctlib.get_value(table[i].value,
523 val, context->bct);
524 if (e) {
525 printf("Error looking up token %d.\n", table[i].value);
526 printf("\"%s\" is not valid for this chip.\n",
527 table[i].name);
528 *val = -1;
529 }
530
531 rest = statement + strlen(table[i].name);
532 return rest;
533 }
534 }
535 return parse_u32(statement, val);
536
537}
Peer Chen8d782ee2011-01-18 21:34:18 -0500538/*
539 * parse_bootloader(): Processes commands to set a bootloader.
540 */
541static int parse_bootloader(build_image_context *context,
542 parse_token token,
543 char *rest)
544{
545 char filename[MAX_BUFFER];
546 char e_state[MAX_STR_LEN];
547 u_int32_t load_addr;
548 u_int32_t entry_point;
549
550 assert(context != NULL);
551 assert(rest != NULL);
552
Peer Chen7557d9b2011-02-24 09:29:23 -0800553 if (context->generate_bct != 0)
554 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500555 /* Parse the file name. */
556 rest = parse_filename(rest, filename, MAX_BUFFER);
557 if (rest == NULL)
558 return 1;
559
560 PARSE_COMMA(1);
561
562 /* Parse the load address. */
563 rest = parse_u32(rest, &load_addr);
564 if (rest == NULL)
565 return 1;
566
567 PARSE_COMMA(1);
568
569 /* Parse the entry point. */
570 rest = parse_u32(rest, &entry_point);
571 if (rest == NULL)
572 return 1;
573
574 PARSE_COMMA(1);
575
576 /* Parse the end state. */
577 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
578 if (rest == NULL)
579 return 1;
580 if (strncmp(e_state, "Complete", strlen("Complete")))
581 return 1;
582
583 /* Parsing has finished - set the bootloader */
584 return set_bootloader(context, filename, load_addr, entry_point);
585}
586
587/*
588 * parse_array(): Processes commands to set an array value.
589 */
590static int
591parse_array(build_image_context *context, parse_token token, char *rest)
592{
593 u_int32_t index;
594 u_int32_t value;
595
596 assert(context != NULL);
597 assert(rest != NULL);
598
599 /* Parse the index. */
600 rest = parse_u32(rest, &index);
601 if (rest == NULL)
602 return 1;
603
604 /* Parse the closing bracket. */
605 if (*rest != ']')
606 return 1;
607 rest++;
608
609 /* Parse the equals sign.*/
610 if (*rest != '=')
611 return 1;
612 rest++;
613
614 /* Parse the value based on the field table. */
615 switch(token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800616 case token_attribute:
617 rest = parse_u32(rest, &value);
618 break;
619 case token_dev_type:
620 rest = parse_enum(context, rest, s_devtype_table, &value);
621 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500622
Peer Chen7557d9b2011-02-24 09:29:23 -0800623 default:
624 /* Unknown token */
625 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500626 }
627
628 if (rest == NULL)
629 return 1;
630
631 /* Store the result. */
632 return context_set_array(context, index, token, value);
633}
634
635/*
636 * parse_value_u32(): General handler for setting u_int32_t values in config files.
637 */
638static int parse_value_u32(build_image_context *context,
639 parse_token token,
640 char *rest)
641{
642 u_int32_t value;
643
644 assert(context != NULL);
645 assert(rest != NULL);
646
647 rest = parse_u32(rest, &value);
648 if (rest == NULL)
649 return 1;
650
651 return context_set_value(context, token, value);
652}
653
654static int
655parse_bct_file(build_image_context *context, parse_token token, char *rest)
656{
657 char filename[MAX_BUFFER];
658
659 assert(context != NULL);
660 assert(rest != NULL);
661
662 /* Parse the file name. */
663 rest = parse_filename(rest, filename, MAX_BUFFER);
664 if (rest == NULL)
665 return 1;
666
667 /* Parsing has finished - set the bctfile */
668 context->bct_filename = filename;
669 /* Read the bct file to buffer */
670 read_bct_file(context);
671 return 0;
672}
673
674static char *
675parse_string(char *statement, char *uname, int chars_remaining)
676{
677 memset(uname, 0, chars_remaining);
678 while (((*statement >= '0') && (*statement <= '9')) ||
679 ((*statement >= 'A') && (*statement <= 'Z')) ||
680 ((*statement >= 'a') && (*statement <= 'z'))) {
681
682 *uname++ = *statement++;
683 if (--chars_remaining < 0) {
684 printf("String length beyond the boundary!!!");
685 return NULL;
686 }
687 }
688 *uname = '\0';
689 return statement;
690}
691
692static char *
693parse_end_state(char *statement, char *uname, int chars_remaining)
694{
695 while (((*statement >= 'a') && (*statement <= 'z')) ||
696 ((*statement >= 'A') && (*statement <= 'Z'))) {
697
698 *uname++ = *statement++;
699 if (--chars_remaining < 0)
700 return NULL;
701 }
702 *uname = '\0';
703 return statement;
704}
705
706
707/* Parse the addon component */
708static int
709parse_addon(build_image_context *context, parse_token token, char *rest)
710{
711 char filename[MAX_BUFFER];
712 char u_name[4];
713 char e_state[MAX_STR_LEN];
714 u_int32_t index;
715 u_int32_t item_attr;
716 u_int32_t others;
717 char other_str[MAX_STR_LEN];
718
719 assert(context != NULL);
720 assert(rest != NULL);
721
722 /* Parse the index. */
723 rest = parse_u32(rest, &index);
724 if (rest == NULL)
725 return 1;
726
727 /* Parse the closing bracket. */
728 if (*rest != ']')
729 return 1;
730 rest++;
731
732 /* Parse the equals sign.*/
733 if (*rest != '=')
734 return 1;
735 rest++;
736
737 rest = parse_filename(rest, filename, MAX_BUFFER);
738 if (rest == NULL)
739 return 1;
740 if (set_addon_filename(context, filename, index) != 0)
741 return 1;
742
743 PARSE_COMMA(1);
744
745 rest = parse_string(rest, u_name, 3);
746 if (rest == NULL) {
747 printf("Unique name should be 3 characters.\n");
748 return 1;
749 }
750 if (set_unique_name(context, u_name, index) != 0)
751 return 1;
752
753 PARSE_COMMA(1);
754
755 rest = parse_u32(rest, &item_attr);
756 if (rest == NULL)
757 return 1;
758 if (set_addon_attr(context, item_attr, index) != 0)
759 return 1;
760
761 PARSE_COMMA(1);
762
763 if (*rest == '0' && (*(rest + 1) == 'x' ||*(rest + 1) == 'X')) {
764 rest = parse_u32(rest, &others);
765 if (set_other_field(context, NULL, others, index) != 0)
766 return 1;
767 } else {
768 rest = parse_string(rest, other_str, 16);
769 if (set_other_field(context, other_str, 0, index) != 0)
770 return 1;
771 }
772 if (rest == NULL)
773 return 1;
774
775 PARSE_COMMA(1);
776
777 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
778 if (rest == NULL)
779 return 1;
780 if (strncmp(e_state, "Complete", strlen("Complete")))
781 return 1;
782 return 0;
783}
784
Peer Chen7557d9b2011-02-24 09:29:23 -0800785static int
786parse_dev_param(build_image_context *context, parse_token token, char *rest)
787{
788 u_int32_t i;
789 u_int32_t value;
790 field_item *field;
791 u_int32_t index;
792 parse_subfield_item *device_item = NULL;
793
794 assert(context != NULL);
795 assert(rest != NULL);
796
797 /* Parse the index. */
798 rest = parse_u32(rest, &index);
799 if (rest == NULL)
800 return 1;
801
802 /* Parse the closing bracket. */
803 if (*rest != ']')
804 return 1;
805 rest++;
806
807 /* Parse the following '.' */
808 if (*rest != '.')
809 return 1;
810 rest++;
811
812 /* Parse the device name. */
813 for (i = 0; s_device_type_table[i].prefix != NULL; i++) {
814 if (!strncmp(s_device_type_table[i].prefix,
815 rest, strlen(s_device_type_table[i].prefix))) {
816
817 device_item = &(s_device_type_table[i]);
818 rest = rest + strlen(s_device_type_table[i].prefix);
819
820 /* Parse the field name. */
821 rest = parse_field_name(rest,
822 s_device_type_table[i].field_table,
823 &field);
824 if (rest == NULL)
825 return 1;
826
827 /* Parse the equals sign.*/
828 if (*rest != '=')
829 return 1;
830 rest++;
831
832 /* Parse the value based on the field table. */
833 rest = parse_field_value(context, rest, field, &value);
834 if (rest == NULL)
835 return 1;
836 return device_item->process(context,
837 index, field->token, value);
838 }
839 }
840
841 return 1;
842
843}
Peer Chen3a834ed2011-03-04 09:30:05 -0800844
845static int
846parse_sdram_param(build_image_context *context, parse_token token, char *rest)
847{
848 u_int32_t value;
849 field_item *field;
850 u_int32_t index;
851
852 assert(context != NULL);
853 assert(rest != NULL);
854
855 /* Parse the index. */
856 rest = parse_u32(rest, &index);
857 if (rest == NULL)
858 return 1;
859
860 /* Parse the closing bracket. */
861 if (*rest != ']')
862 return 1;
863 rest++;
864
865 /* Parse the following '.' */
866 if (*rest != '.')
867 return 1;
868 rest++;
869
870 /* Parse the field name. */
871 rest = parse_field_name(rest, s_sdram_field_table, &field);
872 if (rest == NULL)
873 return 1;
874
875 /* Parse the equals sign.*/
876 if (*rest != '=')
877 return 1;
878 rest++;
879
880 /* Parse the value based on the field table. */
881 rest = parse_field_value(context, rest, field, &value);
882 if (rest == NULL)
883 return 1;
884
885 /* Store the result. */
886 return set_sdram_param(context, index, field->token, value);
887
888}
Peer Chen8d782ee2011-01-18 21:34:18 -0500889/* Return 0 on success, 1 on error */
890static int
891process_statement(build_image_context *context, char *statement)
892{
893 int i;
894 char *rest;
895
896 for (i = 0; s_top_level_items[i].prefix != NULL; i++) {
897 if (!strncmp(s_top_level_items[i].prefix, statement,
898 strlen(s_top_level_items[i].prefix))) {
899 rest = statement + strlen(s_top_level_items[i].prefix);
900
901 return s_top_level_items[i].process(context,
902 s_top_level_items[i].token,
903 rest);
904 }
905 }
906
907 /* If this point was reached, there was a processing error. */
908 return 1;
909}
910
911/* Note: Basic parsing borrowed from nvcamera_config.c */
912void process_config_file(build_image_context *context)
913{
914 char buffer[MAX_BUFFER];
915 int space = 0;
916 char current;
917 u_int8_t c_eol_comment_start = 0; // True after first slash
918 u_int8_t comment = 0;
919 u_int8_t string = 0;
920 u_int8_t equal_encounter = 0;
921
922 assert(context != NULL);
923 assert(context->config_file != NULL);
924
925 while ((current = fgetc(context->config_file)) !=EOF) {
926 if (space >= (MAX_BUFFER-1)) {
927 /* if we exceeded the max buffer size, it is likely
928 due to a missing semi-colon at the end of a line */
929 printf("Config file parsing error!");
930 exit(1);
931 }
932
933 /* Handle failure to complete "//" comment token.
934 Insert the '/' into the busffer and proceed with
935 processing the current character. */
936 if (c_eol_comment_start && current != '/') {
937 c_eol_comment_start = 0;
938 buffer[space++] = '/';
939 }
940
941 switch (current) {
942 case '\"': /* " indicates start or end of a string */
943 if (!comment) {
944 string ^= 1;
945 buffer[space++] = current;
946 }
947 break;
948 case ';':
949 if (!string && !comment) {
950 buffer[space++] = '\0';
951
952 /* Process a statement. */
953 if (process_statement(context, buffer)) {
954 goto error;
955 }
956 space = 0;
957 equal_encounter = 0;
958 } else if (string) {
959 buffer[space++] = current;
960 }
961 break;
962
963 case '/':
964 if (!string && !comment) {
965 if (c_eol_comment_start) {
966 /* EOL comment started. */
967 comment = 1;
968 c_eol_comment_start = 0;
969 } else {
970 /* Potential start of eol comment. */
971 c_eol_comment_start = 1;
972 }
973 } else if (!comment) {
974 buffer[space++] = current;
975 }
976 break;
977
978 /* ignore whitespace. uses fallthrough */
979 case '\n':
980 case '\r': /* carriage returns end comments */
981 string = 0;
982 comment = 0;
983 c_eol_comment_start = 0;
984 case ' ':
985 case '\t':
986 if (string) {
987 buffer[space++] = current;
988 }
989 break;
990
991 case '#':
992 if (!string) {
993 comment = 1;
994 } else {
995 buffer[space++] = current;
996 }
997 break;
998
999 default:
1000 if (!comment) {
1001 buffer[space++] = current;
1002 if (current == '=') {
1003 if (!equal_encounter) {
1004 equal_encounter = 1;
1005 } else {
1006 goto error;
1007 }
1008 }
1009 }
1010 break;
1011 }
1012 }
1013
1014 return;
1015
1016 error:
1017 printf("Error parsing: %s\n", buffer);
1018 exit(1);
1019}