Edit

openbios/fcode-utils/detok/pcihdr.c

Branch :

  • Show log

    Commit

  • Author : Stefan Reinauer
    Date : 2006-10-14 21:32:13
    Hash : 1fcdb9d5
    Message : fix indentation git-svn-id: svn://coreboot.org/openbios/fcode-utils@96 f158a5a8-5612-0410-a976-696ce0be7e32

  • detok/pcihdr.c
  • /*
     *                     OpenBIOS - free your system!
     *                         ( FCode tokenizer )
     *
     *  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
     *
     */
    
    /* **************************************************************************
     *
     *      Support function for de-tokenizer.
     *
     *      Identify and process PCI header at beginning of FCode binary file.
     *      "Processing" consists of recognizing the PCI Header and Data Structure,
     *      optionally printing a description thereof, and (mainly) allowing
     *      the given pointer to be bumped to the start of the actual FCode.
     *
     *
     *      (C) Copyright 2005 IBM Corporation.  All Rights Reserved.
     *      Module Author:  David L. Paktor    dlpaktor@us.ibm.com
     *
     *      Revision History:
     *
     *      Updated Mon, 23 May 2005 by David L. Paktor
     *          Identify "Not Last" header.
     *      Updated Thu, 24 Feb 2005 by David L. Paktor
     *          Per notes after Code Review.
     *      Updated Fri, 04 Feb 2005 by David L. Paktor
     *      Updated Wed, 08 Jun 2005 by David L. Paktor
     *         Added support for multiple-PCI-image files.
     *
     *
     **************************************************************************** */
    
    /* **************************************************************************
     *
     *      Functions Eported:
     *          handle_pci_header
     *              Handle all activities connected with presence of
     *              PCI Header/Data at beginning of FCode file, and
     *              facilitate "skipping" over to actual FCode data.
     *
     *          handle_pci_filler
     *          Skip past "filler" between blocks in multi-PCI-image files.
     *              
     *
     **************************************************************************** */
    
    
    /* **************************************************************************
     *
     *      Still to be done:
     *          Print (as remarks) full descriptions of headers' fields
     *          Error check for wrong "Format"
     *          Skip past non-FCode blocks, thru multiple data-blocks
     *          Recognize PCI header in unexpected place or out-of-place
     *
     **************************************************************************** */
    
    #include "pcihdr.h"
    #include <stdio.h>
    
    #include "detok.h"
    
    
    /* **************************************************************************
     *
     *          Global Variables Exported
     *      pci_image_end           Pointer to just after end of current PCI image
     *
     **************************************************************************** */
    
    u8 *pci_image_end = NULL;
    
    /* **************************************************************************
     *
     *          Internal Static Variables
     *      pci_image_len           Length (in bytes) of current PCI image
     *
     **************************************************************************** */
    
    static int pci_image_len = 0;
    
    
    /* **************************************************************************
     *
     *      Function name:  is_pci_header ( rom_header_t *pci_rom_hdr )
     *      Synopsis:   Indicate whether given pointer is pointing to
     *                  something that might be a valid PCI header
     *      
     *      Inputs:
     *          Parameters:     
     *              pci_rom_hdr    pointer to start of data-stream to examine.
     *                          Treat as pointer to rom_header_t
     *
     *      Outputs:
     *          Returned Value: An integer.
     *               0                  Definitely *NOT* a PCI header
     *              Positive Number     Appears to be a valid PCI header;
     *                                      value is offset to PCI Data Structure.
     *              Negative Number     Appears to be a PCI header, but
     *                                      with errors. (Not Implemented Yet.
     *                                      See under "Still to be done".)
     *
     *      Error Detection:
     *              (See under "Still to be done".)
     *
     *      Process Explanation:
     *          Examine "signature" location for known value  0x55aa
     *          If a match, return value of "dptr" (Data-pointer offset) field.
     *
     *      Revision History:
     *          Created Tue, 01 Feb 2005 by David L. Paktor
     *
     *      Still to be done:
     *          Error-check; look for inconsistencies:
     *              Return a Negative Number if data-stream appears to be a PCI
     *              header, but has erroneous or inconsistent sub-field contents.
     *              Value and meaning of the Negative Number yet to be defined.
     *
     **************************************************************************** */
    
    static int is_pci_header(rom_header_t * pci_rom_hdr)
    {
    	const u16 pci_header_signature = 0x55aa;
    	int retval;
    
    	retval = 0;
    
    	if (BIG_ENDIAN_WORD_FETCH(pci_rom_hdr->signature) == pci_header_signature) {
    		retval = LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr);
    	}
    	return (retval);
    }
    
    /* **************************************************************************
     *
     *      Function name:  is_pci_data_struct ( pci_data_t *pci_data_ptr )
     *      Synopsis:       Indicate whether given pointer is pointing to
     *                      a valid PCI Data Structure
     *      
     *      Inputs:
     *          Parameters:     
     *              pci_data_ptr    pointer to start of data-stream to examine.
     *                          Treat as pointer to pci_data_t 
     *
     *      Outputs:
     *          Returned Value: An integer.
     *                   0                  Definitely *NOT* a PCI Data Structure
     *              Positive Number         Appears to be valid PCI Data Structure;
     *                                      value is length of PCI Data Structure,
     *                                      (presumably, offset to start of FCode).
     *              Negative Number         Appears to be a PCI Data Structure,
     *                                      but with errors. (Not Implemented Yet.
     *                                      See under "Still to be done".)
     *
     *          Global/Static Variables:
     *              Does not alter the poiner passed-in;
     *              does not alter any Global/Static Variables
     *          Printout:       NONE
     *
     *      Error Detection:        (Condition)     (Action)
     *              (See under "Still to be done".)
     *
     *      Process Explanation:
     *          Examine "signature" location for known value "PCIR"
     *          If a match, return value of "dlen" (Data Structure Length) field.
     *      
     *      Revision History:
     *          Created Tue, 01 Feb 2005 by David L. Paktor
     *
     *      Still to be done:
     *          Error-check; look for wrong "Code Type" or other inconsistencies:
     *              Return a Negative Number if data-stream appears to be a
     *              valid PCI Data Structure, but has erroneous or inconsistent
     *              sub-field contents.
     *              Value and meaning of the Negative Number yet to be defined.
     *          Skip past non-FCode data-blocks, even multiple blocks
     *
     **************************************************************************** */
    
    static int is_pci_data_struct(pci_data_t * pci_data_ptr)
    {
    	int retval;
    
    	retval = 0;
    
    	if (BIG_ENDIAN_LONG_FETCH(pci_data_ptr->signature) == PCI_DATA_HDR) {
    		retval = LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen);
    	}
    	return (retval);
    }
    
    
    /* **************************************************************************
     *
     *      Function name:  announce_pci_hdr ( rom_header_t *pci_rom_hdr )
     *      Synopsis:       Print indication that the PCI header was found,
     *                      and other details, formatted as FORTH remarks.
     *      
     *      Inputs:
     *              Parameters:
     *                      pci_rom_hdr        Pointer to start of PCI header.
     *
     *      Outputs:
     *              Returned Value: NONE
     *              Printout:       Announcement.  Size of  data_ptr  field.
     *
     **************************************************************************** */
    
    static void announce_pci_hdr(rom_header_t * pci_rom_hdr)
    {
    	char temp_buf[80];
    	u32 temp;
    
    	printremark("PCI Header identified");
    	temp = (u32) LITTLE_ENDIAN_WORD_FETCH(pci_rom_hdr->data_ptr);
    	sprintf(temp_buf, "  Offset to Data Structure = 0x%04x (%d)\n",
    		temp, temp);
    	printremark(temp_buf);
    }
    
    /* **************************************************************************
     *
     *      Function name:  announce_pci_data_struct ( pci_data_t *pci_data_ptr )
     *      Synopsis:       Print indication that the PCI Data Structure
     *                      was found, and some additional details.
     *                      Format as FORTH remarks.
     *      
     *      Inputs:
     *          Parameters:
     *              pci_data_ptr        Pointer to start of PCI Data Structure.
     *
     *      Outputs:
     *          Returned Value: NONE    
     *          Global/Static Variables:    
     *              pci_image_len      Updated to byte-length of current PCI image
     *          Printout:       (See Synopsis)
     *      
     *      Process Explanation:
     *          Extract some details, format and print them,
     *              using the syntax of FORTH remarks.
     *
     *      Revision History:
     *          Created Tue, 01 Feb 2005 by David L. Paktor
     *          Updated Wed, 25 May 2005 by David L. Paktor
     *               Added printout of several fields...
     *
     **************************************************************************** */
    
    static void announce_pci_data_struct(pci_data_t * pci_data_ptr)
    {
    	char temp_buf[80];
    	u32 temp;
    
    	printremark("PCI Data Structure identified");
    
    	temp = (u32) LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->dlen);
    	sprintf(temp_buf, "  Data Structure Length = 0x%04x (%d)\n", temp, temp);
    	printremark(temp_buf);
    
    	sprintf(temp_buf, "  Vendor ID: 0x%04x\n",
    		LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vendor));
    	printremark(temp_buf);
    
    	sprintf(temp_buf, "  Device ID: 0x%04x\n",
    		LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->device));
    	printremark(temp_buf);
    
    	temp = (u32) CLASS_CODE_FETCH(pci_data_ptr->class_code);
    	sprintf(temp_buf, "  Class Code: 0x%06x  (%s)",
    		temp, pci_device_class_name(temp));
    	printremark(temp_buf);
    
    	temp = (u32) LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->vpd);
    	if (temp != 0) {
    		sprintf(temp_buf, "  Vital Prod Data: 0x%02x\n", temp);
    		printremark(temp_buf);
    	}
    
    	temp = (u32) LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->irevision);
    	if (temp != 0) {
    		sprintf(temp_buf, "  Image Revision: 0x%02x\n", temp);
    		printremark(temp_buf);
    	}
    
    	sprintf(temp_buf, "  Code Type: 0x%02x (%s)\n",
    		pci_data_ptr->code_type,
    		pci_code_type_name(pci_data_ptr->code_type));
    	printremark(temp_buf);
    
    	temp = (u32) LITTLE_ENDIAN_WORD_FETCH(pci_data_ptr->ilen);
    	pci_image_len = temp * 512;
    	sprintf(temp_buf, "  Image Length: 0x%04x blocks (%d bytes)\n",
    		temp, pci_image_len);
    	printremark(temp_buf);
    
    	sprintf(temp_buf, "  %sast PCI Image.\n",
    		pci_data_ptr->last_image_flag && 0x80 != 0 ? "L" : "Not l");
    	printremark(temp_buf);
    
    }
    
    
    /* **************************************************************************
     *
     *      Function name:  handle_pci_header
     *      Synopsis:       Handle PCI Header/Data at beginning of FCode file;
     *                      facilitate "skipping" over to actual FCode data.
     *      
     *      Inputs:
     *          Parameters:     
     *              data_ptr           Pointer to start of data-stream to examine.
     *          Global/Static Variables:        
     *              pci_image_len      Length (in bytes) of current PCI image
     *
     *      Outputs:
     *          Returned Value:
     *              Positive Number.        Offset to start of FCode.
     *              Zero                    If no PCI header; may be treated as
     *                                          a valid offset.
     *              Negative Number         PCI header or PCI Data Structure test
     *                                          returned error indication.
     *                                         (Not Implemented Yet.  See
     *                                          under "Still to be done".)
     *          Global/Static Variables:        
     *              pci_image_end           Pointer to just after the end of
     *                                          the current PCI image
     *          Printout:       As FORTH remarks, print indications that the
     *                          PCI header was found, and maybe later more data.
     *
     *      Error Detection:        (Condition)     (Action)
     *              (See under "Still to be done".)
     *      
     *      Process Explanation:
     *          Use the various support routines defined below.
     *      
     *      
     *      Revision History:
     *
     *      Updated Wed, 09 Feb 2005 by David L. Paktor
     *          Extracted assignments from within  if( )  statements.
     *
     *      Created Tue, 01 Feb 2005 by David L. Paktor
     *
     *      Still to be done:
     *          Handle error cases.  At present, neither  is_pci_header()
     *              nor  is_pci_data_struct()  returns a negative number,
     *              but when they are modified to do so, we must handle it.
     *
     **************************************************************************** */
    
    int handle_pci_header(u8 * data_ptr)
    {
    	int hdrlen;
    	int data_struc_len;
    	/*  int retval;  *//*  Not needed until we handle error cases...  */
    
    	data_struc_len = 0;
    
    	hdrlen = is_pci_header((rom_header_t *) data_ptr);
    	/*  retval = hdrlen;  *//*  Not needed yet...  */
    	if (hdrlen < 0) {
    		/*  Handle error case...  */
    		/*  Leave null for now...  */
    		/*  It might need to do a premature EXIT here...  */
    	} else {
    		/* if hdrlen == 0 then we don't need to check a Data Structure  */
    		if (hdrlen > 0) {
    			announce_pci_hdr((rom_header_t *) data_ptr);
    			data_struc_len = is_pci_data_struct((pci_data_t *) & data_ptr[hdrlen]);
    			/*
    			 *  A Data Structure Length of Zero would be an error
    			 *  that could be detected by  is_pci_data_struct()
    			 */
    			if (data_struc_len <= 0) {
    				/*  Handle error case...  */
    				/*  Leave null for now...  */
    				/*  It might need to do a premature EXIT here...  */
    				/*  retval = -1;   *//*  Not needed yet...  */
    			} else {
    				announce_pci_data_struct((pci_data_t *) & data_ptr[hdrlen]);
    				pci_image_end = data_ptr + pci_image_len;
    				/* retval = hdrlen+data_struc_len; *//*  Not needed yet... */
    			}
    		}
    	}
    	return (hdrlen + data_struc_len);
    }
    
    
    /* **************************************************************************
     *
     *      Function name:  handle_pci_filler
     *      Synopsis:       Examine and report on the "filler" padding after the
     *                      end of an FCode-block but still within a PCI-image
     *
     *      Inputs:
     *         Parameters:
     *             filler_ptr         Pointer to start of PCI-filler in data-stream
     *         Global/Static Variables:    
     *             pci_image_end      Pointer to just after the end of
     *                                          the current PCI image
     *
     *      Outputs:
     *         Returned Value:        NONE
     *         Printout:
     *             Descriptive message.
     *
     *      Error Detection:
     *          Non-zero filler field.  Different message.
     *
     *      Process Explanation:
     *          The calling routine has checked that there was, indeed, a PCI
     *              header present, so we know that pci_image_end is valid.
     *          If the entire filler is zero-bytes, print a simple message and
     *              we're out'a here!
     *          If there are non-zero bytes, identify loc'n of first non-zero.
     *
     *      Still to be done:
     *          Come up with something more elegant for non-zero filler.
     *
     **************************************************************************** */
    
    void handle_pci_filler(u8 * filler_ptr)
    {
    	u8 *scan_ptr;
    	int filler_len;
    	char temp_buf[80];
    	bool all_zero = TRUE;
    	u8 filler_byte = *filler_ptr;
    
    	filler_len = pci_image_end - filler_ptr;
    
    	for (scan_ptr = filler_ptr;
    	     scan_ptr < pci_image_end; filler_byte = *(++scan_ptr)) {
    		if (filler_byte != 0) {
    			all_zero = FALSE;
    			break;
    		}
    	}
    
    	if (all_zero) {
    		sprintf(temp_buf, "PCI Image padded with %d bytes of zero", filler_len);
    	} else {
    		sprintf(temp_buf, "PCI Image padding-field of %d bytes "
    			"had first non-zero byte at offset %ld",
    			filler_len, scan_ptr - filler_ptr);
    	}
    	printremark(temp_buf);
    }