Hash :
d89219a0
Author :
Date :
2017-06-08T18:57:07
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 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
/*
* 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-2010 Stefan Reinauer
*
* 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
**************************************************************************** */
/* **************************************************************************
*
* Still to be done:
* Re-arrange routine and variable locations to clarify the
* functions of this file and its companion, stream.c
* This file should be concerned primarily with management
* of the Outputs; stream.c should be primarily concerned
* with management of the Inputs.
* Hard to justify, pragmatically, but will make for easier
* maintainability down the proverbial road...
*
**************************************************************************** */
#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
*
**************************************************************************** */
/* **************************************************************************
*
* Global Variables Exported:
* opc Output Buffer Position Counter
* pci_hdr_end_ob_off Offsets into Output Buffer of end
* of last PCI Header Block structure
* (To help match up the offset printed in Tokenization_error()
* with the offsets shown by the DeTokenizer)
*
**************************************************************************** */
unsigned int opc = 0;
unsigned int pci_hdr_end_ob_off = 0; /* 0 means "Not initialized" */
/* **************************************************************************
*
* 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 Output-related Local Static and Global
* 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;
opc = 0;
pci_hdr_end_ob_off = 0;
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 )
{
u32 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++) ) ;
if (sun_style_checksum) {
/* SUN OPB on the SPARC (Enterprise) platforms (especially):
* M3000, M4000, M9000 expects a checksum algorithm that is
* not compliant with IEEE 1275-1994 section 5.2.2.5.
*/
checksum = (checksum & 0xffff) + (checksum >> 16);
checksum = (checksum & 0xffff) + (checksum >> 16);
}
BIG_ENDIAN_WORD_STORE(fcode_hdr->checksum,
(u16)(checksum & 0xffff));
BIG_ENDIAN_LONG_STORE(fcode_hdr->length , length);
if (verbose)
{
printf( "toke: checksum is 0x%04x (%d bytes). ",
(u16)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:
* opc Output Buffer Position Counter
* fcode_start_ob_off Initted if FCode output has begun
* noerrors The "Ignore Errors" flag
*
* Outputs:
* Returned Value: NONE
* Global Variables:
* pci_hdr_end_ob_off Set to the Output Buffer Position
* Counter after the PCI Header
* FCode Output buffer
* :The beginning of the PCI Header will be entered, waiting for
* the fields that could not be determined until the end
* to be filled in.
*
* 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();
pci_hdr_end_ob_off = opc;
}
/* **************************************************************************
*
* 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;
pci_hdr_end_ob_off = 0;
}
/* **************************************************************************
*
* Function name: finish_headers
* Synopsis: Fill-in the fields of the FCode- and PCI- Headers
* that could not be determined until the end.
*
*************************************************************************** */
void finish_headers(void)
{
if (fcode_hdr_ob_off != -1) finish_fcodehdr();
if (pci_hdr_ob_off != -1) finish_pcihdr();
}