undirom.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <pxe.h>
00025 #include <realmode.h>
00026 #include <undirom.h>
00027 
00028 /** @file
00029  *
00030  * UNDI expansion ROMs
00031  *
00032  */
00033 
00034 /** List of all UNDI ROMs */
00035 static LIST_HEAD ( undiroms );
00036 
00037 /**
00038  * Parse PXE ROM ID structure
00039  *
00040  * @v undirom           UNDI ROM
00041  * @v pxeromid          Offset within ROM to PXE ROM ID structure
00042  * @ret rc              Return status code
00043  */
00044 static int undirom_parse_pxeromid ( struct undi_rom *undirom,
00045                                    unsigned int pxeromid ) {
00046         struct undi_rom_id undi_rom_id;
00047         unsigned int undiloader;
00048 
00049         DBGC ( undirom, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom,
00050                undirom->rom_segment, pxeromid );
00051 
00052         /* Read PXE ROM ID structure and verify */
00053         copy_from_real ( &undi_rom_id, undirom->rom_segment, pxeromid,
00054                          sizeof ( undi_rom_id ) );
00055         if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
00056                 DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
00057                        "%08x\n", undirom, undi_rom_id.Signature );
00058                 return -EINVAL;
00059         }
00060 
00061         /* Check for UNDI loader */
00062         undiloader = undi_rom_id.UNDILoader;
00063         if ( ! undiloader ) {
00064                 DBGC ( undirom, "UNDIROM %p has no UNDI loader\n", undirom );
00065                 return -EINVAL;
00066         }
00067 
00068         /* Fill in UNDI ROM loader fields */
00069         undirom->loader_entry.segment = undirom->rom_segment;
00070         undirom->loader_entry.offset = undiloader;
00071         undirom->code_size = undi_rom_id.CodeSize;
00072         undirom->data_size = undi_rom_id.DataSize;
00073 
00074         DBGC ( undirom, "UNDIROM %p has UNDI loader at %04x:%04x "
00075                "(code %04zx data %04zx)\n", undirom,
00076                undirom->loader_entry.segment, undirom->loader_entry.offset,
00077                undirom->code_size, undirom->data_size );
00078         return 0;
00079 }
00080 
00081 /**
00082  * Parse PCI expansion header
00083  *
00084  * @v undirom           UNDI ROM
00085  * @v pcirheader        Offset within ROM to PCI expansion header
00086  */
00087 static int undirom_parse_pcirheader ( struct undi_rom *undirom,
00088                                      unsigned int pcirheader ) {
00089         struct pcir_header pcir_header;
00090 
00091         DBGC ( undirom, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
00092                undirom, undirom->rom_segment, pcirheader );
00093 
00094         /* Read PCI expansion header and verify */
00095         copy_from_real ( &pcir_header, undirom->rom_segment, pcirheader,
00096                          sizeof ( pcir_header ) );
00097         if ( pcir_header.signature != PCIR_SIGNATURE ) {
00098                 DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
00099                        "signature %08x\n", undirom, pcir_header.signature );
00100                 return -EINVAL;
00101         }
00102 
00103         /* Fill in UNDI ROM PCI device fields */
00104         undirom->bus_type = PCI_NIC;
00105         undirom->bus_id.pci.vendor_id = pcir_header.vendor_id;
00106         undirom->bus_id.pci.device_id = pcir_header.device_id;
00107 
00108         DBGC ( undirom, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom,
00109                undirom->bus_id.pci.vendor_id, undirom->bus_id.pci.device_id );
00110         return 0;
00111         
00112 }
00113 
00114 /**
00115  * Probe UNDI ROM
00116  *
00117  * @v rom_segment       ROM segment address
00118  * @ret rc              Return status code
00119  */
00120 static int undirom_probe ( unsigned int rom_segment ) {
00121         struct undi_rom *undirom = NULL;
00122         struct undi_rom_header romheader;
00123         size_t rom_len;
00124         unsigned int pxeromid;
00125         unsigned int pcirheader;
00126         int rc;
00127 
00128         /* Read expansion ROM header and verify */
00129         copy_from_real ( &romheader, rom_segment, 0, sizeof ( romheader ) );
00130         if ( romheader.Signature != ROM_SIGNATURE ) {
00131                 rc = -EINVAL;
00132                 goto err;
00133         }
00134         rom_len = ( romheader.ROMLength * 512 );
00135 
00136         /* Allocate memory for UNDI ROM */
00137         undirom = zalloc ( sizeof ( *undirom ) );
00138         if ( ! undirom ) {
00139                 DBG ( "Could not allocate UNDI ROM structure\n" );
00140                 rc = -ENOMEM;
00141                 goto err;
00142         }
00143         DBGC ( undirom, "UNDIROM %p trying expansion ROM at %04x:0000 "
00144                "(%zdkB)\n", undirom, rom_segment, ( rom_len / 1024 ) );
00145         undirom->rom_segment = rom_segment;
00146 
00147         /* Check for and parse PXE ROM ID */
00148         pxeromid = romheader.PXEROMID;
00149         if ( ! pxeromid ) {
00150                 DBGC ( undirom, "UNDIROM %p has no PXE ROM ID\n", undirom );
00151                 rc = -EINVAL;
00152                 goto err;
00153         }
00154         if ( pxeromid > rom_len ) {
00155                 DBGC ( undirom, "UNDIROM %p PXE ROM ID outside ROM\n",
00156                        undirom );
00157                 rc = -EINVAL;
00158                 goto err;
00159         }
00160         if ( ( rc = undirom_parse_pxeromid ( undirom, pxeromid ) ) != 0 )
00161                 goto err;
00162 
00163         /* Parse PCIR header, if present */
00164         pcirheader = romheader.PCIRHeader;
00165         if ( pcirheader )
00166                 undirom_parse_pcirheader ( undirom, pcirheader );
00167 
00168         /* Add to UNDI ROM list and return */
00169         DBGC ( undirom, "UNDIROM %p registered\n", undirom );
00170         list_add ( &undirom->list, &undiroms );
00171         return 0;
00172 
00173  err:
00174         free ( undirom );
00175         return rc;
00176 }
00177 
00178 /**
00179  * Create UNDI ROMs for all possible expansion ROMs
00180  *
00181  * @ret 
00182  */
00183 static void undirom_probe_all_roms ( void ) {
00184         static int probed = 0;
00185         unsigned int rom_segment;
00186 
00187         /* Perform probe only once */
00188         if ( probed )
00189                 return;
00190 
00191         DBG ( "Scanning for PXE expansion ROMs\n" );
00192 
00193         /* Scan through expansion ROM region at 512 byte intervals */
00194         for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
00195               rom_segment += 0x20 ) {
00196                 undirom_probe ( rom_segment );
00197         }
00198 
00199         probed = 1;
00200 }
00201 
00202 /**
00203  * Find UNDI ROM for PCI device
00204  *
00205  * @v vendor_id         PCI vendor ID
00206  * @v device_id         PCI device ID
00207  * @v rombase           ROM base address, or 0 for any
00208  * @ret undirom         UNDI ROM, or NULL
00209  */
00210 struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
00211                                      unsigned int device_id,
00212                                      unsigned int rombase ) {
00213         struct undi_rom *undirom;
00214 
00215         undirom_probe_all_roms();
00216 
00217         list_for_each_entry ( undirom, &undiroms, list ) {
00218                 if ( undirom->bus_type != PCI_NIC )
00219                         continue;
00220                 if ( undirom->bus_id.pci.vendor_id != vendor_id )
00221                         continue;
00222                 if ( undirom->bus_id.pci.device_id != device_id )
00223                         continue;
00224                 if ( rombase && ( ( undirom->rom_segment << 4 ) != rombase ) )
00225                         continue;
00226                 DBGC ( undirom, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
00227                        undirom, vendor_id, device_id, rombase );
00228                 return undirom;
00229         }
00230 
00231         DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
00232               vendor_id, device_id, rombase );
00233         return NULL;
00234 }

Generated on Tue Apr 6 20:00:49 2010 for gPXE by  doxygen 1.5.7.1