1 : /*
2 : * OpenBIOS - free your system!
3 : * ( FCode tokenizer )
4 : *
5 : * emit.c - fcode emitter.
6 : *
7 : * This program is part of a free implementation of the IEEE 1275-1994
8 : * Standard for Boot (Initialization Configuration) Firmware.
9 : *
10 : * Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
11 : *
12 : * This program is free software; you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation; version 2 of the License.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
24 : *
25 : */
26 :
27 : /* **************************************************************************
28 : * Modifications made in 2005 by IBM Corporation
29 : * (C) Copyright 2005 IBM Corporation. All Rights Reserved.
30 : * Modifications Author: David L. Paktor dlpaktor@us.ibm.com
31 : **************************************************************************** */
32 :
33 : #include <stdio.h>
34 : #include <stdlib.h>
35 : #include <string.h>
36 : #include <unistd.h>
37 :
38 : #include "pcihdr.h"
39 :
40 : #include "toke.h"
41 : #include "vocabfuncts.h"
42 : #include "stack.h"
43 : #include "scanner.h"
44 : #include "emit.h"
45 : #include "clflags.h"
46 : #include "errhandler.h"
47 : #include "stream.h"
48 : #include "nextfcode.h"
49 :
50 : /* **************************************************************************
51 : *
52 : * Global Variables Imported
53 : * verbose Enable optional messages, set by "-v" switch
54 : * noerrors "Ignore Errors" flag, set by "-i" switch
55 : *
56 : **************************************************************************** */
57 :
58 :
59 : /* **************************************************************************
60 : *
61 : * Macro to zero-fill a field of the size of the given structure
62 : * into the Output Buffer using the emit_byte() routine.
63 : *
64 : **************************************************************************** */
65 :
66 : #define EMIT_STRUCT(x) {int j; for (j=0; j < sizeof(x) ; j++ ) emit_byte(0); }
67 :
68 :
69 : /* **************************************************************************
70 : *
71 : * Local Static Variables, offsets into Output Buffer of ...:
72 : * fcode_start_ob_off First FCode-Start byte
73 : * fcode_hdr_ob_off FCode Header (Format byte)
74 : * fcode_body_ob_off First functional FCode after FCode Header.
75 : * pci_hdr_ob_off Start of PCI ROM Header Block structure
76 : * pci_data_blk_ob_off Start of PCI Data Header Block structure
77 : *
78 : * For all of these, -1 means "Not initialized"
79 : *
80 : *************************************************************************** */
81 :
82 : static int fcode_start_ob_off = -1;
83 : static int fcode_hdr_ob_off = -1;
84 : static int fcode_body_ob_off = -1;
85 : static int pci_hdr_ob_off = -1;
86 : static int pci_data_blk_ob_off = -1;
87 :
88 : /* **************************************************************************
89 : *
90 : * These are to detect a particular error: If FCode has
91 : * been written, before an Fcode-start<n> or before
92 : * a PCI-header
93 : *
94 : **************************************************************************** */
95 :
96 : static bool fcode_written = FALSE;
97 :
98 : /* **************************************************************************
99 : *
100 : * Variables and Functions Imported, with
101 : * Exposure as Limited as possible:
102 : * ostart
103 : * olen
104 : * increase_output_buffer
105 : *
106 : **************************************************************************** */
107 :
108 : extern u8 *ostart;
109 : extern int olen;
110 : extern void increase_output_buffer( void);
111 :
112 :
113 : /* **************************************************************************
114 : *
115 : * Function name: init_emit
116 : * Synopsis: Initialize Local Static Variables before starting
117 : * Output.
118 : * Exposure as Limited as possible.
119 : *
120 : **************************************************************************** */
121 : void init_emit( void); /* Prototype. Limit Exposure. */
122 : void init_emit( void)
123 165 : {
124 165 : fcode_start_ob_off = -1;
125 165 : fcode_hdr_ob_off = -1;
126 165 : fcode_body_ob_off = -1;
127 165 : pci_hdr_ob_off = -1;
128 165 : pci_data_blk_ob_off = -1;
129 165 : fcode_written = FALSE;
130 165 : haveend = FALSE; /* Get this one too... */
131 165 : }
132 :
133 :
134 : /* **************************************************************************
135 : *
136 : * Function name: emit_byte
137 : * Synopsis: Fundamental routine for placing a byte
138 : * into the Output Buffer. Also, check
139 : * whether the buffer needs to be expanded.
140 : * For internal use only.
141 : *
142 : **************************************************************************** */
143 :
144 : static void emit_byte(u8 data)
145 1854072 : {
146 1854072 : if ( opc == olen)
147 : {
148 6 : increase_output_buffer();
149 : }
150 :
151 :
152 1854072 : *(ostart+opc) = data ;
153 1854072 : opc++;
154 1854072 : }
155 :
156 : void emit_fcode(u16 tok)
157 155237 : {
158 155237 : if ((tok>>8))
159 11989 : emit_byte(tok>>8);
160 :
161 155237 : emit_byte(tok&0xff);
162 155237 : fcode_written = TRUE;
163 155237 : }
164 :
165 : static void emit_num32(u32 num)
166 10696 : {
167 10696 : emit_byte(num>>24);
168 10696 : emit_byte((num>>16)&0xff);
169 10696 : emit_byte((num>>8)&0xff);
170 10696 : emit_byte(num&0xff);
171 :
172 10696 : }
173 :
174 : /* **************************************************************************
175 : *
176 : * Function name: user_emit_byte
177 : * Synopsis: Action of user-mandated call to emit-byte.
178 : * Covers the corner-case where this is the
179 : * first command issued in the source input.
180 : *
181 : **************************************************************************** */
182 :
183 : void user_emit_byte(u8 data)
184 48 : {
185 48 : emit_byte( data);
186 48 : fcode_written = TRUE;
187 48 : }
188 :
189 : void emit_offset(s16 offs)
190 5900 : {
191 : /* Calling routine will test for out-of-range FCode-Offset */
192 5900 : if (offs16)
193 5863 : emit_byte(offs>>8);
194 5900 : emit_byte(offs&0xff);
195 5900 : }
196 :
197 : void emit_literal(u32 num)
198 10696 : {
199 10696 : emit_token("b(lit)");
200 10696 : emit_num32(num);
201 10696 : }
202 :
203 : void emit_string(u8 *string, signed int cnt)
204 45244 : {
205 45244 : signed int i=0;
206 45244 : signed int cnt_cpy = cnt;
207 :
208 45244 : if ( cnt_cpy > STRING_LEN_MAX )
209 : {
210 0 : tokenization_error( TKERROR,
211 : "String too long: %d characters. Truncating.\n",cnt);
212 0 : cnt_cpy = STRING_LEN_MAX ;
213 : }
214 45244 : emit_byte(cnt_cpy);
215 1618894 : for (i=0; i<cnt_cpy; i++)
216 1573650 : emit_byte(string[i]);
217 45244 : }
218 :
219 : void emit_fcodehdr(const char *starter_name)
220 170 : {
221 :
222 : /* Check for error conditions */
223 170 : if ( fcode_written )
224 : {
225 3 : tokenization_error( TKERROR ,
226 : "Cannot create FCode header after FCode output has begun.\n");
227 3 : if ( ! noerrors ) return ;
228 : }
229 :
230 : fcode_header_t *fcode_hdr;
231 :
232 170 : fcode_start_ob_off = opc;
233 170 : emit_token( starter_name );
234 :
235 170 : fcode_hdr_ob_off = opc;
236 170 : fcode_hdr = (fcode_header_t *)(ostart+fcode_hdr_ob_off);
237 :
238 170 : EMIT_STRUCT(fcode_header_t);
239 :
240 170 : fcode_body_ob_off = opc;
241 :
242 : /* Format = 8 means we comply with IEEE 1275-1994 */
243 170 : fcode_hdr->format = 0x08;
244 :
245 : }
246 :
247 : /* **************************************************************************
248 : *
249 : * Function name: finish_fcodehdr
250 : * Fill in the FCode header's checksum and length fields, and
251 : * reset the FCode-header pointer for the next image.
252 : *
253 : * If haveend is true then the end0 has already been written
254 : * and fcode_ender() has been called.
255 : *
256 : * Print a WARNING message if the end-of-file was encountered
257 : * without an end0 or an fcode-end
258 : *
259 : * Print an informative message to standard-output giving the
260 : * checksum. Call list_fcode_ranges() to print the
261 : * value of the last FCode-token that was assigned or
262 : * the Ranges of assigned FCode-token values if so be...
263 : * The final FCode-binary file-length will be printed
264 : * when the binary file is being closed.
265 : *
266 : **************************************************************************** */
267 :
268 : void finish_fcodehdr(void)
269 175 : {
270 :
271 175 : if( fcode_hdr_ob_off == -1 )
272 : {
273 1 : tokenization_error( TKERROR,
274 : "Missing FCode header.\n");
275 1 : return ;
276 : }
277 :
278 : /* If the program did not end cleanly, we'll handle it */
279 174 : if (!haveend)
280 : {
281 5 : tokenization_error ( WARNING,
282 : "End-of-file encountered without END0 or FCODE-END. "
283 : "Supplying END0\n");
284 5 : emit_token("end0");
285 5 : fcode_ender();
286 : }
287 :
288 : /* Calculate and place checksum and length, if haven't already */
289 174 : if ( fcode_start_ob_off != -1 )
290 : {
291 : u16 checksum;
292 : int length;
293 :
294 169 : u8 *fcode_body = ostart+fcode_body_ob_off;
295 169 : u8 *ob_end = ostart+opc;
296 : fcode_header_t *fcode_hdr =
297 169 : (fcode_header_t *)(ostart+fcode_hdr_ob_off);
298 :
299 169 : length = opc - fcode_start_ob_off;
300 :
301 169 : for ( checksum = 0;
302 1829098 : fcode_body < ob_end ;
303 1828760 : checksum += *(fcode_body++) ) ;
304 :
305 169 : BIG_ENDIAN_WORD_STORE(fcode_hdr->checksum , checksum);
306 169 : BIG_ENDIAN_LONG_STORE(fcode_hdr->length , length);
307 :
308 169 : if (verbose)
309 : {
310 168 : printf( "toke: checksum is 0x%04x (%d bytes). ",
311 : checksum, length);
312 168 : list_fcode_ranges( TRUE);
313 : }
314 : }
315 :
316 : /* Reset things for the next image... */
317 174 : fcode_start_ob_off = -1;
318 174 : fcode_hdr_ob_off = -1;
319 174 : fcode_body_ob_off = -1;
320 174 : fcode_written = FALSE;
321 174 : haveend=FALSE;
322 : }
323 :
324 : /* **************************************************************************
325 : *
326 : * Function name: emit_pci_rom_hdr
327 : * Synopsis: Write the PCI ROM Header Block into the Output Buffer
328 : *
329 : * Inputs:
330 : * Parameters: NONE
331 : * Global Variables:
332 : * opc Output Buffer Position Counter
333 : * ostart Start of Output Buffer
334 : *
335 : * Outputs:
336 : * Returned Value: NONE
337 : * Global Variables:
338 : * pci_hdr_ob_off PCI ROM Header Block Position
339 : * (Offset) in Output Buffer
340 : * FCode Output buffer:
341 : * Write the part of the PCI ROM Header Block we know:
342 : * Fill in the signature and the field reserved for
343 : * "processor architecture unique data".
344 : * Fill in the "Pointer to PCI Data Structure" with the
345 : * size of the data structure, because the first PCI
346 : * Data Structure will follow immediately.
347 : *
348 : * Error Detection: (Handled by calling routine)
349 : *
350 : **************************************************************************** */
351 :
352 : static void emit_pci_rom_hdr(void)
353 30 : {
354 : rom_header_t *pci_hdr;
355 30 : pci_hdr_ob_off = opc;
356 30 : pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
357 :
358 30 : EMIT_STRUCT(rom_header_t);
359 :
360 : /* PCI start signature */
361 30 : LITTLE_ENDIAN_WORD_STORE(pci_hdr->signature,0xaa55);
362 :
363 : /* Processor architecture */
364 : /* Note:
365 : * The legacy code used to read:
366 : *
367 : * pci_hdr->reserved[0] = 0x34;
368 : *
369 : * I don't know what significance the literal 34 had, but
370 : * by what might just be an odd coincidence, it is equal
371 : * to the combined lengths of the PCI-ROM- and PCI-Data-
372 : * headers.
373 : *
374 : * I suspect that it is more than merely an odd coincidence,
375 : * and that the following would be preferable:
376 : */
377 :
378 30 : LITTLE_ENDIAN_WORD_STORE( pci_hdr->reserved ,
379 : (sizeof(rom_header_t) + sizeof(pci_data_t)) ) ;
380 :
381 : /* already handled padding */
382 :
383 : /* pointer to start of PCI data structure */
384 30 : LITTLE_ENDIAN_WORD_STORE(pci_hdr->data_ptr, sizeof(rom_header_t) );
385 :
386 30 : }
387 :
388 : /* **************************************************************************
389 : *
390 : * Function name: emit_pci_data_block
391 : * Synopsis: Write the PCI Data Block into the Output Buffer
392 : *
393 : * Inputs:
394 : * Parameters: NONE
395 : * Global Variables:
396 : * opc Output Buffer Position Counter
397 : * Data-Stack Items:
398 : * Top: Class Code
399 : * Next: Device ID
400 : * 3rd: Vendor ID
401 : *
402 : * Outputs:
403 : * Returned Value: NONE
404 : * Global Variables:
405 : * pci_data_blk_ob_off PCI Data Header Block Position
406 : * (Offset) in Output Buffer
407 : * Data-Stack, # of Items Popped: 3
408 : * FCode Output buffer:
409 : * Write the PCI Data Header Block: Fill in the signature,
410 : * Vendor ID, Device ID and Class Code, and everything
411 : * else whose value we know. (Size and Checksum will
412 : * have to wait until we finish the image...)
413 : * Printout:
414 : * Advisory of Vendor, Device and Class
415 : *
416 : * Error Detection: (Handled by calling routine)
417 : *
418 : **************************************************************************** */
419 :
420 : static void emit_pci_data_block(void)
421 30 : {
422 : pci_data_t *pci_data_blk;
423 30 : u32 class_id = dpop();
424 30 : u16 dev_id = dpop();
425 30 : u16 vend_id = dpop();
426 :
427 30 : pci_data_blk_ob_off = opc;
428 30 : pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
429 :
430 30 : EMIT_STRUCT(pci_data_t);
431 :
432 30 : BIG_ENDIAN_LONG_STORE(pci_data_blk->signature , PCI_DATA_HDR );
433 :
434 30 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vendor , vend_id );
435 30 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->device , dev_id );
436 30 : LITTLE_ENDIAN_TRIPLET_STORE(pci_data_blk->class_code , class_id );
437 :
438 30 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->dlen , sizeof(pci_data_t) );
439 :
440 30 : pci_data_blk->drevision = PCI_DATA_STRUCT_REV ;
441 :
442 : /* code type = open firmware = 1 */
443 30 : pci_data_blk->code_type = 1;
444 :
445 : /* last image flag */
446 30 : pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
447 :
448 30 : tokenization_error(INFO ,
449 : "PCI header vendor id=0x%04x, "
450 : "device id=0x%04x, class=%06x\n",
451 : vend_id, dev_id, class_id );
452 :
453 30 : }
454 :
455 : /* **************************************************************************
456 : *
457 : * Function name: emit_pcihdr
458 : * Synopsis: Supervise the writing of PCI Header information
459 : * into the Output Buffer, when the PCI-HEADER
460 : * tokenizer directive has been encountered.
461 : *
462 : * Inputs:
463 : * Parameters: NONE
464 : * Global Variables:
465 : * fcode_start_ob_off Initted if FCode output has begun
466 : * noerrors The "Ignore Errors" flag
467 : *
468 : * Outputs:
469 : * Returned Value: NONE
470 : * Global Variables:
471 : * FCode Output buffer:
472 : *
473 : * Error Detection:
474 : * An attempt to write a PCI Header after FCode output -- either an
475 : * Fcode-start<n> or ordinary FCode -- has begun is an ERROR.
476 : * Report it; do nothing further, unless "Ignore Errors" is set.
477 : *
478 : **************************************************************************** */
479 :
480 : void emit_pcihdr(void)
481 30 : {
482 :
483 : /* Check for error conditions */
484 30 : if (
485 : /* FCODE-START<n> has already been issued */
486 : ( fcode_start_ob_off != -1 )
487 : /* Other FCode has been written */
488 : || fcode_written
489 : )
490 : {
491 1 : tokenization_error( TKERROR ,
492 : "Cannot create PCI header after FCode output has begun.\n");
493 1 : if ( ! noerrors ) return ;
494 : }
495 :
496 30 : emit_pci_rom_hdr();
497 :
498 30 : emit_pci_data_block();
499 : }
500 :
501 : /* **************************************************************************
502 : *
503 : * Function name: finish_pcihdr
504 : * Synopsis: Fill-in the fields of the PCI Header that could
505 : * not be determined until the end of the PCI-block.
506 : *
507 : *************************************************************************** */
508 :
509 : void finish_pcihdr(void)
510 30 : {
511 :
512 : u32 imagesize ;
513 : u32 imageblocks;
514 : int padding;
515 :
516 : rom_header_t *pci_hdr;
517 : pci_data_t *pci_data_blk;
518 :
519 30 : if( pci_data_blk_ob_off == -1 )
520 : {
521 0 : tokenization_error( TKERROR,
522 : "%s without PCI-HEADER\n", strupr(statbuf) );
523 0 : return ;
524 : }
525 :
526 30 : pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
527 30 : pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
528 :
529 : /* fix up vpd */
530 30 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vpd, pci_vpd);
531 :
532 : /* Calculate image size and padding */
533 30 : imagesize = opc - pci_hdr_ob_off; /* Padding includes PCI hdr */
534 30 : imageblocks = (imagesize + 511) >> 9; /* Size in 512-byte blocks */
535 30 : padding = (imageblocks << 9) - imagesize;
536 :
537 : /* fix up image size. */
538 30 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->ilen, imageblocks);
539 :
540 : /* fix up revision */
541 30 : if ( big_end_pci_image_rev )
542 : {
543 2 : BIG_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
544 : }else{
545 28 : LITTLE_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
546 : }
547 :
548 : /* fix up last image flag */
549 30 : pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
550 :
551 : /* align to 512bytes */
552 :
553 30 : printf("Adding %d bytes of zero padding to PCI image.\n",padding);
554 10667 : while (padding--)
555 10607 : emit_byte(0);
556 30 : if ( ! pci_is_last_image )
557 : {
558 12 : printf("Note: PCI header is not last image.\n");
559 : }
560 30 : printf("\n");
561 :
562 30 : pci_hdr_ob_off = -1;
563 30 : pci_data_blk_ob_off = -1;
564 : }
565 :
566 : void finish_headers(void)
567 164 : {
568 164 : if (fcode_hdr_ob_off != -1) finish_fcodehdr();
569 164 : if (pci_hdr_ob_off != -1) finish_pcihdr();
570 164 : }
571 :
|