blob: 0cfe820c205606e45e838792ffa952b5b2ab3051 [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 },
Peer Chen56f40482011-07-27 02:59:41 -0400350 { "Bctcopy=", token_bct_copy, parse_value_u32 },
Peer Chen053d5782011-03-03 10:12:58 -0800351 { "Version=", token_version, parse_value_u32 },
352 { "AddOn[", token_addon, parse_addon },
Peer Chen8d782ee2011-01-18 21:34:18 -0500353 { NULL, 0, NULL } /* Must be last */
354};
355
356/* Macro to simplify parser code a bit. */
357#define PARSE_COMMA(x) if (*rest != ',') return (x); rest++
358
359/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
360/* Returns the address of the character after the parsed data. */
361static char *
362parse_u32(char *statement, u_int32_t *val)
363{
364 u_int32_t value = 0;
365
366 while (*statement=='0') {
367 statement++;
368 }
369
370 if (*statement=='x' || *statement=='X') {
371 statement++;
372 while (((*statement >= '0') && (*statement <= '9')) ||
373 ((*statement >= 'a') && (*statement <= 'f')) ||
374 ((*statement >= 'A') && (*statement <= 'F'))) {
375 value *= 16;
376 if ((*statement >= '0') && (*statement <= '9')) {
377 value += (*statement - '0');
378 } else if ((*statement >= 'A') &&
379 (*statement <= 'F')) {
380 value += ((*statement - 'A')+10);
381 } else {
382 value += ((*statement - 'a')+10);
383 }
384 statement++;
385 }
386 } else {
387 while (*statement >= '0' && *statement <= '9') {
388 value = value*10 + (*statement - '0');
389 statement++;
390 }
391 }
392 *val = value;
393 return statement;
394}
395
Peer Chen7557d9b2011-02-24 09:29:23 -0800396char *
397parse_u8(char *statement, u_int32_t *val)
398{
399 char *retval;
400
401 retval = parse_u32(statement, val);
402
403 if (*val > 0xff) {
404 printf("Warning: Parsed 8-bit value that exceeded 8-bits.\n");
405 printf(" Parsed value = %d. Remaining text = %s\n",
406 *val, retval);
407 }
408
409 return retval;
410}
411
412
Peer Chen8d782ee2011-01-18 21:34:18 -0500413/* This parsing code was initially borrowed from nvcamera_config_parse.c. */
414/* Returns the address of the character after the parsed data. */
415static char *
416parse_filename(char *statement, char *name, int chars_remaining)
417{
418 while (((*statement >= '0') && (*statement <= '9')) ||
419 ((*statement >= 'a') && (*statement <= 'z')) ||
420 ((*statement >= 'A') && (*statement <= 'Z')) ||
421 (*statement == '\\') ||
422 (*statement == '/' ) ||
423 (*statement == '~' ) ||
424 (*statement == '_' ) ||
425 (*statement == '-' ) ||
426 (*statement == '+' ) ||
427 (*statement == ':' ) ||
428 (*statement == '.' )) {
429 /* Check if the filename buffer is out of space, preserving one
430 * character to null terminate the string.
431 */
432 chars_remaining--;
433
434 if (chars_remaining < 1)
435 return NULL;
436 *name++ = *statement++;
437 }
438
439 /* Null terminate the filename. */
440 *name = '\0';
441
442 return statement;
443}
444
Peer Chen7557d9b2011-02-24 09:29:23 -0800445static char
446*parse_field_name(char *rest, field_item *field_table, field_item **field)
447{
448 u_int32_t i;
449 u_int32_t field_name_len = 0;
450
451 assert(field_table != NULL);
452 assert(rest != NULL);
453 assert(field != NULL);
454
455 while(*(rest + field_name_len) != '=')
456 field_name_len++;
457
458 /* Parse the field name. */
459 for (i = 0; field_table[i].name != NULL; i++) {
460 if ((strlen(field_table[i].name) == field_name_len) &&
461 !strncmp(field_table[i].name,
462 rest,
463 field_name_len)) {
464
465 *field = &(field_table[i]);
466 rest = rest + field_name_len;
467 return rest;
468 }
469 }
470
471 /* Field wasn't found or a parse error occurred. */
472 return NULL;
473}
474
475static char
476*parse_field_value(build_image_context *context,
477 char *rest,
478 field_item *field,
479 u_int32_t *value)
480{
481 assert(rest != NULL);
482 assert(field != NULL);
483 assert((field->type != field_type_enum)
484 || (field->enum_table != NULL));
485
486 switch (field->type) {
487 case field_type_enum:
488 rest = parse_enum(context, rest, field->enum_table, value);
489 break;
490
491 case field_type_u32:
492 rest = parse_u32(rest, value);
493 break;
494
495 case field_type_u8:
496 rest = parse_u8(rest, value);
497 break;
498
499 default:
500 printf("Unexpected field type %d at line %d\n",
501 field->type, __LINE__);
502 rest = NULL;
503 break;
504 }
505
506 return rest;
507}
508
509static char *
510parse_enum(build_image_context *context,
511 char *statement,
512 enum_item *table,
513 u_int32_t *val)
514{
515 int i;
516 char *rest;
517 int e;
518
519 for (i = 0; table[i].name != NULL; i++) {
520 if (!strncmp(table[i].name, statement,
521 strlen(table[i].name))) {
522 /* Lookup the correct value for the token. */
523 e = context->bctlib.get_value(table[i].value,
524 val, context->bct);
525 if (e) {
526 printf("Error looking up token %d.\n", table[i].value);
527 printf("\"%s\" is not valid for this chip.\n",
528 table[i].name);
529 *val = -1;
530 }
531
532 rest = statement + strlen(table[i].name);
533 return rest;
534 }
535 }
536 return parse_u32(statement, val);
537
538}
Peer Chen8d782ee2011-01-18 21:34:18 -0500539/*
540 * parse_bootloader(): Processes commands to set a bootloader.
541 */
542static int parse_bootloader(build_image_context *context,
543 parse_token token,
544 char *rest)
545{
546 char filename[MAX_BUFFER];
547 char e_state[MAX_STR_LEN];
548 u_int32_t load_addr;
549 u_int32_t entry_point;
550
551 assert(context != NULL);
552 assert(rest != NULL);
553
Peer Chen7557d9b2011-02-24 09:29:23 -0800554 if (context->generate_bct != 0)
555 return 0;
Peer Chen8d782ee2011-01-18 21:34:18 -0500556 /* Parse the file name. */
557 rest = parse_filename(rest, filename, MAX_BUFFER);
558 if (rest == NULL)
559 return 1;
560
561 PARSE_COMMA(1);
562
563 /* Parse the load address. */
564 rest = parse_u32(rest, &load_addr);
565 if (rest == NULL)
566 return 1;
567
568 PARSE_COMMA(1);
569
570 /* Parse the entry point. */
571 rest = parse_u32(rest, &entry_point);
572 if (rest == NULL)
573 return 1;
574
575 PARSE_COMMA(1);
576
577 /* Parse the end state. */
578 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
579 if (rest == NULL)
580 return 1;
581 if (strncmp(e_state, "Complete", strlen("Complete")))
582 return 1;
583
584 /* Parsing has finished - set the bootloader */
585 return set_bootloader(context, filename, load_addr, entry_point);
586}
587
588/*
589 * parse_array(): Processes commands to set an array value.
590 */
591static int
592parse_array(build_image_context *context, parse_token token, char *rest)
593{
594 u_int32_t index;
595 u_int32_t value;
596
597 assert(context != NULL);
598 assert(rest != NULL);
599
600 /* Parse the index. */
601 rest = parse_u32(rest, &index);
602 if (rest == NULL)
603 return 1;
604
605 /* Parse the closing bracket. */
606 if (*rest != ']')
607 return 1;
608 rest++;
609
610 /* Parse the equals sign.*/
611 if (*rest != '=')
612 return 1;
613 rest++;
614
615 /* Parse the value based on the field table. */
616 switch(token) {
Peer Chen7557d9b2011-02-24 09:29:23 -0800617 case token_attribute:
618 rest = parse_u32(rest, &value);
619 break;
620 case token_dev_type:
621 rest = parse_enum(context, rest, s_devtype_table, &value);
622 break;
Peer Chen8d782ee2011-01-18 21:34:18 -0500623
Peer Chen7557d9b2011-02-24 09:29:23 -0800624 default:
625 /* Unknown token */
626 return 1;
Peer Chen8d782ee2011-01-18 21:34:18 -0500627 }
628
629 if (rest == NULL)
630 return 1;
631
632 /* Store the result. */
633 return context_set_array(context, index, token, value);
634}
635
636/*
637 * parse_value_u32(): General handler for setting u_int32_t values in config files.
638 */
639static int parse_value_u32(build_image_context *context,
640 parse_token token,
641 char *rest)
642{
643 u_int32_t value;
644
645 assert(context != NULL);
646 assert(rest != NULL);
647
648 rest = parse_u32(rest, &value);
649 if (rest == NULL)
650 return 1;
651
652 return context_set_value(context, token, value);
653}
654
655static int
656parse_bct_file(build_image_context *context, parse_token token, char *rest)
657{
658 char filename[MAX_BUFFER];
659
660 assert(context != NULL);
661 assert(rest != NULL);
662
663 /* Parse the file name. */
664 rest = parse_filename(rest, filename, MAX_BUFFER);
665 if (rest == NULL)
666 return 1;
667
668 /* Parsing has finished - set the bctfile */
669 context->bct_filename = filename;
670 /* Read the bct file to buffer */
671 read_bct_file(context);
672 return 0;
673}
674
675static char *
676parse_string(char *statement, char *uname, int chars_remaining)
677{
678 memset(uname, 0, chars_remaining);
679 while (((*statement >= '0') && (*statement <= '9')) ||
680 ((*statement >= 'A') && (*statement <= 'Z')) ||
681 ((*statement >= 'a') && (*statement <= 'z'))) {
682
683 *uname++ = *statement++;
684 if (--chars_remaining < 0) {
685 printf("String length beyond the boundary!!!");
686 return NULL;
687 }
688 }
689 *uname = '\0';
690 return statement;
691}
692
693static char *
694parse_end_state(char *statement, char *uname, int chars_remaining)
695{
696 while (((*statement >= 'a') && (*statement <= 'z')) ||
697 ((*statement >= 'A') && (*statement <= 'Z'))) {
698
699 *uname++ = *statement++;
700 if (--chars_remaining < 0)
701 return NULL;
702 }
703 *uname = '\0';
704 return statement;
705}
706
707
708/* Parse the addon component */
709static int
710parse_addon(build_image_context *context, parse_token token, char *rest)
711{
712 char filename[MAX_BUFFER];
713 char u_name[4];
714 char e_state[MAX_STR_LEN];
715 u_int32_t index;
716 u_int32_t item_attr;
717 u_int32_t others;
718 char other_str[MAX_STR_LEN];
719
720 assert(context != NULL);
721 assert(rest != NULL);
722
723 /* Parse the index. */
724 rest = parse_u32(rest, &index);
725 if (rest == NULL)
726 return 1;
727
728 /* Parse the closing bracket. */
729 if (*rest != ']')
730 return 1;
731 rest++;
732
733 /* Parse the equals sign.*/
734 if (*rest != '=')
735 return 1;
736 rest++;
737
738 rest = parse_filename(rest, filename, MAX_BUFFER);
739 if (rest == NULL)
740 return 1;
741 if (set_addon_filename(context, filename, index) != 0)
742 return 1;
743
744 PARSE_COMMA(1);
745
746 rest = parse_string(rest, u_name, 3);
747 if (rest == NULL) {
748 printf("Unique name should be 3 characters.\n");
749 return 1;
750 }
751 if (set_unique_name(context, u_name, index) != 0)
752 return 1;
753
754 PARSE_COMMA(1);
755
756 rest = parse_u32(rest, &item_attr);
757 if (rest == NULL)
758 return 1;
759 if (set_addon_attr(context, item_attr, index) != 0)
760 return 1;
761
762 PARSE_COMMA(1);
763
764 if (*rest == '0' && (*(rest + 1) == 'x' ||*(rest + 1) == 'X')) {
765 rest = parse_u32(rest, &others);
766 if (set_other_field(context, NULL, others, index) != 0)
767 return 1;
768 } else {
769 rest = parse_string(rest, other_str, 16);
770 if (set_other_field(context, other_str, 0, index) != 0)
771 return 1;
772 }
773 if (rest == NULL)
774 return 1;
775
776 PARSE_COMMA(1);
777
778 rest = parse_end_state(rest, e_state, MAX_STR_LEN);
779 if (rest == NULL)
780 return 1;
781 if (strncmp(e_state, "Complete", strlen("Complete")))
782 return 1;
783 return 0;
784}
785
Peer Chen7557d9b2011-02-24 09:29:23 -0800786static int
787parse_dev_param(build_image_context *context, parse_token token, char *rest)
788{
789 u_int32_t i;
790 u_int32_t value;
791 field_item *field;
792 u_int32_t index;
793 parse_subfield_item *device_item = NULL;
794
795 assert(context != NULL);
796 assert(rest != NULL);
797
798 /* Parse the index. */
799 rest = parse_u32(rest, &index);
800 if (rest == NULL)
801 return 1;
802
803 /* Parse the closing bracket. */
804 if (*rest != ']')
805 return 1;
806 rest++;
807
808 /* Parse the following '.' */
809 if (*rest != '.')
810 return 1;
811 rest++;
812
813 /* Parse the device name. */
814 for (i = 0; s_device_type_table[i].prefix != NULL; i++) {
815 if (!strncmp(s_device_type_table[i].prefix,
816 rest, strlen(s_device_type_table[i].prefix))) {
817
818 device_item = &(s_device_type_table[i]);
819 rest = rest + strlen(s_device_type_table[i].prefix);
820
821 /* Parse the field name. */
822 rest = parse_field_name(rest,
823 s_device_type_table[i].field_table,
824 &field);
825 if (rest == NULL)
826 return 1;
827
828 /* Parse the equals sign.*/
829 if (*rest != '=')
830 return 1;
831 rest++;
832
833 /* Parse the value based on the field table. */
834 rest = parse_field_value(context, rest, field, &value);
835 if (rest == NULL)
836 return 1;
837 return device_item->process(context,
838 index, field->token, value);
839 }
840 }
841
842 return 1;
843
844}
Peer Chen3a834ed2011-03-04 09:30:05 -0800845
846static int
847parse_sdram_param(build_image_context *context, parse_token token, char *rest)
848{
849 u_int32_t value;
850 field_item *field;
851 u_int32_t index;
852
853 assert(context != NULL);
854 assert(rest != NULL);
855
856 /* Parse the index. */
857 rest = parse_u32(rest, &index);
858 if (rest == NULL)
859 return 1;
860
861 /* Parse the closing bracket. */
862 if (*rest != ']')
863 return 1;
864 rest++;
865
866 /* Parse the following '.' */
867 if (*rest != '.')
868 return 1;
869 rest++;
870
871 /* Parse the field name. */
872 rest = parse_field_name(rest, s_sdram_field_table, &field);
873 if (rest == NULL)
874 return 1;
875
876 /* Parse the equals sign.*/
877 if (*rest != '=')
878 return 1;
879 rest++;
880
881 /* Parse the value based on the field table. */
882 rest = parse_field_value(context, rest, field, &value);
883 if (rest == NULL)
884 return 1;
885
886 /* Store the result. */
887 return set_sdram_param(context, index, field->token, value);
888
889}
Peer Chen8d782ee2011-01-18 21:34:18 -0500890/* Return 0 on success, 1 on error */
891static int
892process_statement(build_image_context *context, char *statement)
893{
894 int i;
895 char *rest;
896
897 for (i = 0; s_top_level_items[i].prefix != NULL; i++) {
898 if (!strncmp(s_top_level_items[i].prefix, statement,
899 strlen(s_top_level_items[i].prefix))) {
900 rest = statement + strlen(s_top_level_items[i].prefix);
901
902 return s_top_level_items[i].process(context,
903 s_top_level_items[i].token,
904 rest);
905 }
906 }
907
908 /* If this point was reached, there was a processing error. */
909 return 1;
910}
911
912/* Note: Basic parsing borrowed from nvcamera_config.c */
913void process_config_file(build_image_context *context)
914{
915 char buffer[MAX_BUFFER];
916 int space = 0;
917 char current;
918 u_int8_t c_eol_comment_start = 0; // True after first slash
919 u_int8_t comment = 0;
920 u_int8_t string = 0;
921 u_int8_t equal_encounter = 0;
922
923 assert(context != NULL);
924 assert(context->config_file != NULL);
925
926 while ((current = fgetc(context->config_file)) !=EOF) {
927 if (space >= (MAX_BUFFER-1)) {
928 /* if we exceeded the max buffer size, it is likely
929 due to a missing semi-colon at the end of a line */
930 printf("Config file parsing error!");
931 exit(1);
932 }
933
934 /* Handle failure to complete "//" comment token.
935 Insert the '/' into the busffer and proceed with
936 processing the current character. */
937 if (c_eol_comment_start && current != '/') {
938 c_eol_comment_start = 0;
939 buffer[space++] = '/';
940 }
941
942 switch (current) {
943 case '\"': /* " indicates start or end of a string */
944 if (!comment) {
945 string ^= 1;
946 buffer[space++] = current;
947 }
948 break;
949 case ';':
950 if (!string && !comment) {
951 buffer[space++] = '\0';
952
953 /* Process a statement. */
954 if (process_statement(context, buffer)) {
955 goto error;
956 }
957 space = 0;
958 equal_encounter = 0;
959 } else if (string) {
960 buffer[space++] = current;
961 }
962 break;
963
964 case '/':
965 if (!string && !comment) {
966 if (c_eol_comment_start) {
967 /* EOL comment started. */
968 comment = 1;
969 c_eol_comment_start = 0;
970 } else {
971 /* Potential start of eol comment. */
972 c_eol_comment_start = 1;
973 }
974 } else if (!comment) {
975 buffer[space++] = current;
976 }
977 break;
978
979 /* ignore whitespace. uses fallthrough */
980 case '\n':
981 case '\r': /* carriage returns end comments */
982 string = 0;
983 comment = 0;
984 c_eol_comment_start = 0;
985 case ' ':
986 case '\t':
987 if (string) {
988 buffer[space++] = current;
989 }
990 break;
991
992 case '#':
993 if (!string) {
994 comment = 1;
995 } else {
996 buffer[space++] = current;
997 }
998 break;
999
1000 default:
1001 if (!comment) {
1002 buffer[space++] = current;
1003 if (current == '=') {
1004 if (!equal_encounter) {
1005 equal_encounter = 1;
1006 } else {
1007 goto error;
1008 }
1009 }
1010 }
1011 break;
1012 }
1013 }
1014
1015 return;
1016
1017 error:
1018 printf("Error parsing: %s\n", buffer);
1019 exit(1);
1020}