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