Main Page | Data Structures | File List | Data Fields | Globals

emit.c

Go to the documentation of this file.
00001 /*
00002  *                     OpenBIOS - free your system! 
00003  *                         ( FCode tokenizer )
00004  *                          
00005  *  emit.c - fcode emitter.
00006  *  
00007  *  This program is part of a free implementation of the IEEE 1275-1994 
00008  *  Standard for Boot (Initialization Configuration) Firmware.
00009  *
00010  *  Copyright (C) 2001-2005 Stefan Reinauer, <stepan@openbios.org>
00011  *
00012  *  This program is free software; you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation; version 2 of the License.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
00024  *
00025  */
00026 
00027 /* **************************************************************************
00028  *         Modifications made in 2005 by IBM Corporation
00029  *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
00030  *      Modifications Author:  David L. Paktor    dlpaktor@us.ibm.com
00031  **************************************************************************** */
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <unistd.h>
00037 
00038 #include "pcihdr.h"
00039 
00040 #include "toke.h"
00041 #include "vocabfuncts.h"
00042 #include "stack.h"
00043 #include "scanner.h"
00044 #include "emit.h"
00045 #include "clflags.h"
00046 #include "errhandler.h"
00047 #include "stream.h"
00048 #include "nextfcode.h"
00049 
00050 /* **************************************************************************
00051  *
00052  *          Global Variables Imported
00053  *              verbose         Enable optional messages, set by "-v" switch
00054  *              noerrors        "Ignore Errors" flag, set by "-i" switch
00055  *
00056  **************************************************************************** */
00057 
00058 
00059 /* **************************************************************************
00060  *
00061  *      Macro to zero-fill a field of the size of the given structure
00062  *          into the Output Buffer using the  emit_byte()  routine.
00063  *
00064  **************************************************************************** */
00065 
00066 #define EMIT_STRUCT(x)  {int j; for (j=0; j < sizeof(x) ; j++ ) emit_byte(0); }
00067 
00068 
00069 /* **************************************************************************
00070  *
00071  *      Local Static Variables, offsets into Output Buffer of ...:
00072  *          fcode_start_ob_off      First FCode-Start byte
00073  *          fcode_hdr_ob_off        FCode Header (Format byte)
00074  *          fcode_body_ob_off       First functional FCode after FCode Header.
00075  *          pci_hdr_ob_off          Start of PCI ROM Header Block structure
00076  *          pci_data_blk_ob_off     Start of PCI Data Header Block structure
00077  *
00078  *     For all of these, -1 means "Not initialized"
00079  *
00080  *************************************************************************** */
00081 
00082 static  int fcode_start_ob_off = -1;
00083 static  int fcode_hdr_ob_off = -1;
00084 static  int fcode_body_ob_off = -1;
00085 static  int pci_hdr_ob_off = -1;
00086 static  int pci_data_blk_ob_off = -1;
00087 
00088 /* **************************************************************************
00089  *
00090  *          These are to detect a particular error:  If FCode has
00091  *              been written, before an Fcode-start<n> or before
00092  *               a PCI-header
00093  *
00094  **************************************************************************** */
00095 
00096 static bool fcode_written = FALSE;
00097 
00098 /* **************************************************************************
00099  *
00100  *          Variables and Functions Imported, with
00101  *          Exposure as Limited as possible:
00102  *              ostart
00103  *              olen
00104  *              increase_output_buffer
00105  *
00106  **************************************************************************** */
00107 
00108 extern u8 *ostart;
00109 extern int olen;
00110 extern void increase_output_buffer( void);
00111 
00112 
00113 /* **************************************************************************
00114  *
00115  *      Function name:  init_emit
00116  *      Synopsis:       Initialize Local Static Variables before starting
00117  *                          Output.
00118  *                      Exposure as Limited as possible.
00119  *
00120  **************************************************************************** */
00121 void init_emit( void);       /*    Prototype.  Limit Exposure.   */
00122 void init_emit( void)
00123 {
00124     fcode_start_ob_off  = -1;
00125     fcode_hdr_ob_off    = -1;
00126     fcode_body_ob_off   = -1;
00127     pci_hdr_ob_off      = -1;
00128     pci_data_blk_ob_off = -1;
00129     fcode_written       = FALSE;
00130     haveend             = FALSE;   /*  Get this one too...  */
00131 }
00132 
00133 
00134 /* **************************************************************************
00135  *
00136  *      Function name:  emit_byte
00137  *      Synopsis:       Fundamental routine for placing a byte
00138  *                          into the Output Buffer.  Also, check
00139  *                          whether the buffer needs to be expanded.
00140  *                      For internal use only.
00141  *
00142  **************************************************************************** */
00143 
00144 static void emit_byte(u8 data)
00145 {
00146         if ( opc == olen)
00147         {
00148             increase_output_buffer();
00149         }
00150         
00151 
00152         *(ostart+opc) = data ;
00153         opc++;
00154 }
00155 
00156 void emit_fcode(u16 tok)
00157 {
00158         if ((tok>>8))
00159                 emit_byte(tok>>8);
00160 
00161         emit_byte(tok&0xff);
00162         fcode_written = TRUE;
00163 }
00164 
00165 static void emit_num32(u32 num)
00166 {
00167         emit_byte(num>>24);
00168         emit_byte((num>>16)&0xff);
00169         emit_byte((num>>8)&0xff);
00170         emit_byte(num&0xff);
00171 
00172 }
00173 
00174 /* **************************************************************************
00175  *
00176  *      Function name:  user_emit_byte
00177  *      Synopsis:       Action of user-mandated call to emit-byte.
00178  *                          Covers the corner-case where this is the
00179  *                          first command issued in the source input.
00180  *
00181  **************************************************************************** */
00182 
00183 void user_emit_byte(u8 data)
00184 {
00185         emit_byte( data);
00186         fcode_written = TRUE;
00187 }
00188 
00189 void emit_offset(s16 offs)
00190 {
00191     /*  Calling routine will test for out-of-range FCode-Offset  */
00192         if (offs16)
00193                 emit_byte(offs>>8);
00194         emit_byte(offs&0xff);
00195 }
00196 
00197 void emit_literal(u32 num)
00198 {
00199     emit_token("b(lit)");
00200     emit_num32(num);
00201 }
00202 
00203 void emit_string(u8 *string, signed int cnt)
00204 {
00205         signed int i=0;
00206         signed int cnt_cpy = cnt;
00207         
00208         if ( cnt_cpy > STRING_LEN_MAX )
00209         {
00210             tokenization_error( TKERROR,
00211                 "String too long:  %d characters.  Truncating.\n",cnt);
00212             cnt_cpy = STRING_LEN_MAX ;
00213         }
00214         emit_byte(cnt_cpy);
00215         for (i=0; i<cnt_cpy; i++)
00216                 emit_byte(string[i]);
00217 }
00218 
00219 void emit_fcodehdr(const char *starter_name)
00220 {
00221         
00222    /*  Check for error conditions   */
00223     if ( fcode_written )
00224     {
00225         tokenization_error( TKERROR ,
00226             "Cannot create FCode header after FCode output has begun.\n");
00227         if ( ! noerrors ) return ;
00228     }
00229 
00230         fcode_header_t *fcode_hdr;
00231 
00232         fcode_start_ob_off = opc;
00233         emit_token( starter_name );
00234 
00235         fcode_hdr_ob_off = opc;
00236         fcode_hdr = (fcode_header_t *)(ostart+fcode_hdr_ob_off);
00237 
00238         EMIT_STRUCT(fcode_header_t);
00239 
00240         fcode_body_ob_off = opc;
00241 
00242         /* Format = 8 means we comply with IEEE 1275-1994 */
00243         fcode_hdr->format = 0x08;
00244 
00245 }
00246 
00247 /* **************************************************************************
00248  *
00249  *      Function name:    finish_fcodehdr
00250  *          Fill in the FCode header's checksum and length fields, and
00251  *              reset the FCode-header pointer for the next image.
00252  *
00253  *          If  haveend  is true then the end0 has already been written
00254  *              and  fcode_ender()  has been called.
00255  *
00256  *          Print a WARNING message if the end-of-file was encountered
00257  *              without an end0 or an fcode-end
00258  *
00259  *          Print an informative message to standard-output giving the
00260  *              checksum.  Call  list_fcode_ranges()  to print the
00261  *              value of the last FCode-token that was assigned or
00262  *              the Ranges of assigned FCode-token values if so be...
00263  *              The final FCode-binary file-length will be printed
00264  *              when the binary file is being closed.
00265  *
00266  **************************************************************************** */
00267 
00268 void finish_fcodehdr(void)
00269 {
00270 
00271         if( fcode_hdr_ob_off == -1 )
00272         {
00273                 tokenization_error( TKERROR,
00274                     "Missing FCode header.\n");
00275                 return ;
00276         }
00277 
00278         /* If the program did not end cleanly, we'll handle it */
00279         if (!haveend)
00280         {
00281             tokenization_error ( WARNING,
00282             "End-of-file encountered without END0 or FCODE-END.  "
00283                 "Supplying END0\n");
00284                 emit_token("end0");
00285             fcode_ender();
00286         }
00287 
00288         /*  Calculate and place checksum and length, if haven't already  */
00289         if ( fcode_start_ob_off != -1 )
00290         {
00291             u16 checksum;
00292             int length;
00293 
00294             u8 *fcode_body = ostart+fcode_body_ob_off;
00295             u8 *ob_end = ostart+opc;
00296             fcode_header_t *fcode_hdr =
00297                  (fcode_header_t *)(ostart+fcode_hdr_ob_off);
00298         
00299             length = opc - fcode_start_ob_off;
00300 
00301             for ( checksum = 0;
00302                       fcode_body < ob_end ;
00303                           checksum += *(fcode_body++) ) ;
00304 
00305             BIG_ENDIAN_WORD_STORE(fcode_hdr->checksum , checksum);
00306             BIG_ENDIAN_LONG_STORE(fcode_hdr->length , length);
00307 
00308         if (verbose)
00309             {
00310                 printf( "toke: checksum is 0x%04x (%d bytes).  ",
00311                     checksum, length);
00312                 list_fcode_ranges( TRUE);
00313             }
00314         }
00315 
00316         /*  Reset things for the next image...   */
00317         fcode_start_ob_off = -1;
00318         fcode_hdr_ob_off   = -1;
00319         fcode_body_ob_off  = -1;
00320         fcode_written      = FALSE;
00321         haveend=FALSE;
00322 }
00323 
00324 /* **************************************************************************
00325  *
00326  *      Function name:  emit_pci_rom_hdr
00327  *      Synopsis:       Write the PCI ROM Header Block into the Output Buffer
00328  *
00329  *      Inputs:
00330  *         Parameters:                   NONE
00331  *         Global Variables:        
00332  *             opc                       Output Buffer Position Counter
00333  *             ostart                    Start of Output Buffer
00334  *
00335  *      Outputs:
00336  *         Returned Value:               NONE
00337  *         Global Variables:    
00338  *             pci_hdr_ob_off            PCI ROM Header Block Position
00339  *                                           (Offset) in Output Buffer
00340  *         FCode Output buffer:
00341  *             Write the part of the PCI ROM Header Block we know:
00342  *                 Fill in the signature and the field reserved for
00343  *                 "processor architecture unique data".
00344  *             Fill in the "Pointer to PCI Data Structure" with the
00345  *                 size of the data structure, because the first PCI
00346  *                 Data Structure will follow immediately.
00347  *
00348  *      Error Detection:   (Handled by calling routine)
00349  *
00350  **************************************************************************** */
00351 
00352 static void emit_pci_rom_hdr(void)
00353 {
00354     rom_header_t *pci_hdr;
00355     pci_hdr_ob_off = opc;
00356     pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
00357 
00358     EMIT_STRUCT(rom_header_t);
00359         
00360         /* PCI start signature */
00361     LITTLE_ENDIAN_WORD_STORE(pci_hdr->signature,0xaa55);
00362         
00363         /* Processor architecture */
00364         /*  Note:
00365          *  The legacy code used to read:
00366          *
00367          *        pci_hdr->reserved[0] = 0x34;
00368          *
00369          *  I don't know what significance the literal  34  had, but
00370          *      by what might just be an odd coincidence, it is equal
00371          *      to the combined lengths of the  PCI-ROM-  and  PCI-Data-
00372          *      headers.
00373          *
00374          *  I suspect that it is more than merely an odd coincidence,
00375          *      and that the following would be preferable:
00376          */
00377 
00378     LITTLE_ENDIAN_WORD_STORE( pci_hdr->reserved ,
00379         (sizeof(rom_header_t) + sizeof(pci_data_t)) ) ;
00380 
00381         /* already handled padding */
00382 
00383         /* pointer to start of PCI data structure */
00384     LITTLE_ENDIAN_WORD_STORE(pci_hdr->data_ptr, sizeof(rom_header_t) );
00385 
00386 }
00387         
00388 /* **************************************************************************
00389  *
00390  *      Function name:  emit_pci_data_block
00391  *      Synopsis:       Write the PCI Data Block into the Output Buffer
00392  *
00393  *      Inputs:
00394  *         Parameters:                   NONE
00395  *         Global Variables:        
00396  *             opc                       Output Buffer Position Counter
00397  *         Data-Stack Items:
00398  *             Top:                      Class Code
00399  *             Next:                     Device ID
00400  *             3rd:                      Vendor ID
00401  *
00402  *      Outputs:
00403  *         Returned Value:               NONE
00404  *         Global Variables:    
00405  *             pci_data_blk_ob_off       PCI Data Header Block Position
00406  *                                           (Offset) in Output Buffer
00407  *         Data-Stack, # of Items Popped:  3
00408  *         FCode Output buffer:
00409  *             Write the PCI Data Header Block:  Fill in the signature,
00410  *                 Vendor ID, Device ID and Class Code, and everything
00411  *                 else whose value we know.  (Size and Checksum will
00412  *                 have to wait until we finish the image...)
00413  *         Printout:
00414  *             Advisory of Vendor, Device and Class 
00415  *
00416  *      Error Detection:   (Handled by calling routine)
00417  *
00418  **************************************************************************** */
00419 
00420 static void emit_pci_data_block(void)
00421 {
00422     pci_data_t *pci_data_blk;
00423     u32 class_id = dpop();
00424     u16 dev_id   = dpop();
00425     u16 vend_id  = dpop();
00426 
00427     pci_data_blk_ob_off = opc;
00428     pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
00429 
00430     EMIT_STRUCT(pci_data_t);
00431 
00432     BIG_ENDIAN_LONG_STORE(pci_data_blk->signature , PCI_DATA_HDR );
00433 
00434     LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vendor , vend_id );
00435     LITTLE_ENDIAN_WORD_STORE(pci_data_blk->device , dev_id );
00436     LITTLE_ENDIAN_TRIPLET_STORE(pci_data_blk->class_code , class_id );
00437 
00438     LITTLE_ENDIAN_WORD_STORE(pci_data_blk->dlen ,  sizeof(pci_data_t) );
00439 
00440     pci_data_blk->drevision = PCI_DATA_STRUCT_REV ;
00441 
00442         /* code type = open firmware = 1 */
00443     pci_data_blk->code_type = 1;
00444 
00445         /* last image flag */
00446     pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
00447 
00448     tokenization_error(INFO ,
00449         "PCI header vendor id=0x%04x, "
00450             "device id=0x%04x, class=%06x\n",
00451                 vend_id, dev_id, class_id );
00452 
00453 }
00454 
00455 /* **************************************************************************
00456  *
00457  *      Function name:  emit_pcihdr
00458  *      Synopsis:       Supervise the writing of PCI Header information
00459  *                          into the Output Buffer, when the  PCI-HEADER
00460  *                          tokenizer directive has been encountered.
00461  *
00462  *      Inputs:
00463  *         Parameters:                   NONE
00464  *         Global Variables:        
00465  *             fcode_start_ob_off        Initted if FCode output has begun
00466  *             noerrors                  The "Ignore Errors" flag
00467  *
00468  *      Outputs:
00469  *         Returned Value:               NONE
00470  *         Global Variables:    
00471  *         FCode Output buffer:
00472  *
00473  *      Error Detection:
00474  *          An attempt to write a PCI Header after FCode output -- either an
00475  *              Fcode-start<n> or ordinary FCode -- has begun is an ERROR.
00476  *              Report it; do nothing further, unless "Ignore Errors" is set.
00477  *
00478  **************************************************************************** */
00479 
00480 void emit_pcihdr(void)
00481 {
00482 
00483     /*  Check for error conditions   */
00484     if (
00485     /*  FCODE-START<n>  has already been issued  */
00486               ( fcode_start_ob_off != -1 )
00487     /*  Other FCode has been written             */
00488               ||  fcode_written
00489          )
00490     {
00491         tokenization_error( TKERROR ,
00492             "Cannot create PCI header after FCode output has begun.\n");
00493         if ( ! noerrors ) return ;
00494         }
00495 
00496         emit_pci_rom_hdr();
00497 
00498         emit_pci_data_block();
00499 }
00500 
00501 /* **************************************************************************
00502  *
00503  *      Function name:  finish_pcihdr
00504  *      Synopsis:       Fill-in the fields of the PCI Header that could
00505  *                      not be determined until the end of the PCI-block.
00506  *
00507  *************************************************************************** */
00508 
00509 void finish_pcihdr(void)
00510 {
00511 
00512         u32 imagesize ;
00513         u32 imageblocks;
00514         int padding;
00515         
00516         rom_header_t *pci_hdr;
00517         pci_data_t   *pci_data_blk;
00518 
00519         if( pci_data_blk_ob_off == -1 )
00520         {
00521             tokenization_error( TKERROR,
00522                 "%s without PCI-HEADER\n", strupr(statbuf) );
00523             return ;
00524         }
00525 
00526         pci_hdr = (rom_header_t *)(ostart + pci_hdr_ob_off);
00527         pci_data_blk = (pci_data_t *)(ostart + pci_data_blk_ob_off);
00528 
00529         /* fix up vpd */
00530         LITTLE_ENDIAN_WORD_STORE(pci_data_blk->vpd, pci_vpd);
00531 
00532         /*   Calculate image size and padding */
00533         imagesize = opc - pci_hdr_ob_off;     /*  Padding includes PCI hdr  */
00534         imageblocks = (imagesize + 511) >> 9; /*  Size in 512-byte blocks   */
00535         padding = (imageblocks << 9) - imagesize;
00536 
00537         /* fix up image size. */
00538         LITTLE_ENDIAN_WORD_STORE(pci_data_blk->ilen, imageblocks);
00539         
00540         /* fix up revision */
00541         if ( big_end_pci_image_rev )
00542         {
00543             BIG_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
00544         }else{
00545             LITTLE_ENDIAN_WORD_STORE(pci_data_blk->irevision, pci_image_rev);
00546         }
00547         
00548         /* fix up last image flag */
00549         pci_data_blk->last_image_flag = pci_is_last_image ? 0x80 : 0 ;
00550         
00551         /* align to 512bytes */
00552         
00553         printf("Adding %d bytes of zero padding to PCI image.\n",padding);
00554         while (padding--)
00555                 emit_byte(0);
00556         if ( ! pci_is_last_image )
00557         {
00558             printf("Note:  PCI header is not last image.\n");
00559         }
00560         printf("\n");
00561         
00562         pci_hdr_ob_off      = -1;
00563         pci_data_blk_ob_off = -1;
00564 }
00565 
00566 void finish_headers(void)
00567 {
00568         if (fcode_hdr_ob_off != -1) finish_fcodehdr();
00569         if (pci_hdr_ob_off != -1) finish_pcihdr();
00570 }
00571 

Generated on Fri Aug 18 14:03:38 2006 for Toke1.0 by  doxygen 1.4.4