00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00029
00030
00031
00032
00033
00034
00035 static LIST_HEAD ( undiroms );
00036
00037
00038
00039
00040
00041
00042
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
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
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
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
00083
00084
00085
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
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
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
00116
00117
00118
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
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
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
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
00164 pcirheader = romheader.PCIRHeader;
00165 if ( pcirheader )
00166 undirom_parse_pcirheader ( undirom, pcirheader );
00167
00168
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
00180
00181
00182
00183 static void undirom_probe_all_roms ( void ) {
00184 static int probed = 0;
00185 unsigned int rom_segment;
00186
00187
00188 if ( probed )
00189 return;
00190
00191 DBG ( "Scanning for PXE expansion ROMs\n" );
00192
00193
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
00204
00205
00206
00207
00208
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 }