1 /* 2 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. 3 * 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 18 * USA 19 */ 20 21 %locations 22 23 %{ 24 #include <stdio.h> 25 26 #include "dtc.h" 27 #include "srcpos.h" 28 29 extern int yylex(void); 30 31 extern struct boot_info *the_boot_info; 32 extern int treesource_error; 33 34 static unsigned long long eval_literal(const char *s, int base, int bits); 35 %} 36 37 %union { 38 char *propnodename; 39 char *literal; 40 char *labelref; 41 unsigned int cbase; 42 uint8_t byte; 43 struct data data; 44 45 uint64_t addr; 46 cell_t cell; 47 struct property *prop; 48 struct property *proplist; 49 struct node *node; 50 struct node *nodelist; 51 struct reserve_info *re; 52 } 53 54 %token DT_V1 55 %token DT_MEMRESERVE 56 %token <propnodename> DT_PROPNODENAME 57 %token <literal> DT_LITERAL 58 %token <literal> DT_LEGACYLITERAL 59 %token <cbase> DT_BASE 60 %token <byte> DT_BYTE 61 %token <data> DT_STRING 62 %token <labelref> DT_LABEL 63 %token <labelref> DT_REF 64 %token DT_INCBIN 65 66 %type <data> propdata 67 %type <data> propdataprefix 68 %type <re> memreserve 69 %type <re> memreserves 70 %type <re> v0_memreserve 71 %type <re> v0_memreserves 72 %type <addr> addr 73 %type <data> celllist 74 %type <cbase> cellbase 75 %type <cell> cellval 76 %type <data> bytestring 77 %type <prop> propdef 78 %type <proplist> proplist 79 80 %type <node> devicetree 81 %type <node> nodedef 82 %type <node> subnode 83 %type <nodelist> subnodes 84 %type <labelref> label 85 86 %% 87 88 sourcefile: 89 DT_V1 ';' memreserves devicetree 90 { 91 the_boot_info = build_boot_info($3, $4, 0); 92 } 93 | v0_memreserves devicetree 94 { 95 the_boot_info = build_boot_info($1, $2, 0); 96 } 97 ; 98 99 memreserves: 100 /* empty */ 101 { 102 $$ = NULL; 103 } 104 | memreserve memreserves 105 { 106 $$ = chain_reserve_entry($1, $2); 107 } 108 ; 109 110 memreserve: 111 label DT_MEMRESERVE addr addr ';' 112 { 113 $$ = build_reserve_entry($3, $4, $1); 114 } 115 ; 116 117 v0_memreserves: 118 /* empty */ 119 { 120 $$ = NULL; 121 } 122 | v0_memreserve v0_memreserves 123 { 124 $$ = chain_reserve_entry($1, $2); 125 }; 126 ; 127 128 v0_memreserve: 129 memreserve 130 { 131 $$ = $1; 132 } 133 | label DT_MEMRESERVE addr '-' addr ';' 134 { 135 $$ = build_reserve_entry($3, $5 - $3 + 1, $1); 136 } 137 ; 138 139 addr: 140 DT_LITERAL 141 { 142 $$ = eval_literal($1, 0, 64); 143 } 144 | DT_LEGACYLITERAL 145 { 146 $$ = eval_literal($1, 16, 64); 147 } 148 ; 149 150 devicetree: 151 '/' nodedef 152 { 153 $$ = name_node($2, "", NULL); 154 } 155 ; 156 157 nodedef: 158 '{' proplist subnodes '}' ';' 159 { 160 $$ = build_node($2, $3); 161 } 162 ; 163 164 proplist: 165 /* empty */ 166 { 167 $$ = NULL; 168 } 169 | proplist propdef 170 { 171 $$ = chain_property($2, $1); 172 } 173 ; 174 175 propdef: 176 label DT_PROPNODENAME '=' propdata ';' 177 { 178 $$ = build_property($2, $4, $1); 179 } 180 | label DT_PROPNODENAME ';' 181 { 182 $$ = build_property($2, empty_data, $1); 183 } 184 ; 185 186 propdata: 187 propdataprefix DT_STRING 188 { 189 $$ = data_merge($1, $2); 190 } 191 | propdataprefix '<' celllist '>' 192 { 193 $$ = data_merge($1, $3); 194 } 195 | propdataprefix '[' bytestring ']' 196 { 197 $$ = data_merge($1, $3); 198 } 199 | propdataprefix DT_REF 200 { 201 $$ = data_add_marker($1, REF_PATH, $2); 202 } 203 | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' 204 { 205 struct search_path path = { srcpos_file->dir, NULL, NULL }; 206 struct dtc_file *file = dtc_open_file($4.val, &path); 207 struct data d = empty_data; 208 209 if ($6 != 0) 210 if (fseek(file->file, $6, SEEK_SET) != 0) 211 yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", 212 (unsigned long long)$6, 213 $4.val, strerror(errno)); 214 215 d = data_copy_file(file->file, $8); 216 217 $$ = data_merge($1, d); 218 dtc_close_file(file); 219 } 220 | propdataprefix DT_INCBIN '(' DT_STRING ')' 221 { 222 struct search_path path = { srcpos_file->dir, NULL, NULL }; 223 struct dtc_file *file = dtc_open_file($4.val, &path); 224 struct data d = empty_data; 225 226 d = data_copy_file(file->file, -1); 227 228 $$ = data_merge($1, d); 229 dtc_close_file(file); 230 } 231 | propdata DT_LABEL 232 { 233 $$ = data_add_marker($1, LABEL, $2); 234 } 235 ; 236 237 propdataprefix: 238 /* empty */ 239 { 240 $$ = empty_data; 241 } 242 | propdata ',' 243 { 244 $$ = $1; 245 } 246 | propdataprefix DT_LABEL 247 { 248 $$ = data_add_marker($1, LABEL, $2); 249 } 250 ; 251 252 celllist: 253 /* empty */ 254 { 255 $$ = empty_data; 256 } 257 | celllist cellval 258 { 259 $$ = data_append_cell($1, $2); 260 } 261 | celllist DT_REF 262 { 263 $$ = data_append_cell(data_add_marker($1, REF_PHANDLE, 264 $2), -1); 265 } 266 | celllist DT_LABEL 267 { 268 $$ = data_add_marker($1, LABEL, $2); 269 } 270 ; 271 272 cellbase: 273 /* empty */ 274 { 275 $$ = 16; 276 } 277 | DT_BASE 278 ; 279 280 cellval: 281 DT_LITERAL 282 { 283 $$ = eval_literal($1, 0, 32); 284 } 285 | cellbase DT_LEGACYLITERAL 286 { 287 $$ = eval_literal($2, $1, 32); 288 } 289 ; 290 291 bytestring: 292 /* empty */ 293 { 294 $$ = empty_data; 295 } 296 | bytestring DT_BYTE 297 { 298 $$ = data_append_byte($1, $2); 299 } 300 | bytestring DT_LABEL 301 { 302 $$ = data_add_marker($1, LABEL, $2); 303 } 304 ; 305 306 subnodes: 307 /* empty */ 308 { 309 $$ = NULL; 310 } 311 | subnode subnodes 312 { 313 $$ = chain_node($1, $2); 314 } 315 | subnode propdef 316 { 317 yyerror("syntax error: properties must precede subnodes"); 318 YYERROR; 319 } 320 ; 321 322 subnode: 323 label DT_PROPNODENAME nodedef 324 { 325 $$ = name_node($3, $2, $1); 326 } 327 ; 328 329 label: 330 /* empty */ 331 { 332 $$ = NULL; 333 } 334 | DT_LABEL 335 { 336 $$ = $1; 337 } 338 ; 339 340 %% 341 342 void yyerrorf(char const *s, ...) 343 { 344 const char *fname = srcpos_file ? srcpos_file->name : "<no-file>"; 345 va_list va; 346 va_start(va, s); 347 348 if (strcmp(fname, "-") == 0) 349 fname = "stdin"; 350 351 fprintf(stderr, "%s:%d ", fname, yylloc.first_line); 352 vfprintf(stderr, s, va); 353 fprintf(stderr, "\n"); 354 355 treesource_error = 1; 356 va_end(va); 357 } 358 359 void yyerror (char const *s) 360 { 361 yyerrorf("%s", s); 362 } 363 364 static unsigned long long eval_literal(const char *s, int base, int bits) 365 { 366 unsigned long long val; 367 char *e; 368 369 errno = 0; 370 val = strtoull(s, &e, base); 371 if (*e) 372 yyerror("bad characters in literal"); 373 else if ((errno == ERANGE) 374 || ((bits < 64) && (val >= (1ULL << bits)))) 375 yyerror("literal out of range"); 376 else if (errno != 0) 377 yyerror("bad literal"); 378 return val; 379 } 380