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