/*
* 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);
}