1 /************************************************************************** 2 Etherboot - BOOTP/TFTP Bootstrap Program 3 UNDI NIC driver for Etherboot 4 5 This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk> 6 of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights 7 reserved. 8 9 $Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $ 10 ***************************************************************************/ 11 12 /* 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2, or (at 16 * your option) any later version. 17 */ 18 19 /* to get some global routines like printf */ 20 #include "etherboot.h" 21 /* to get the interface to the body of the program */ 22 #include "nic.h" 23 /* to get the PCI support functions, if this is a PCI NIC */ 24 #include "pci.h" 25 /* UNDI and PXE defines. Includes pxe.h. */ 26 #include "undi.h" 27 /* 8259 PIC defines */ 28 #include "pic8259.h" 29 #include "bootp.h" 30 #include "tftp.h" 31 #include "shared.h" 32 33 /* NIC specific static variables go here */ 34 static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 35 NULL, NULL, 0, NULL, 0, NULL, 36 0, 0, 0, 0, 37 { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, NULL }, 38 IRQ_NONE }; 39 static undi_base_mem_data_t undi_base_mem_data; 40 41 #define UNDI_HEAP (void *)(512 << 10) 42 43 /* Function prototypes */ 44 int allocate_base_mem_data ( void ); 45 int free_base_mem_data ( void ); 46 int eb_pxenv_undi_shutdown ( void ); 47 int eb_pxenv_stop_undi ( void ); 48 int undi_unload_base_code ( void ); 49 int undi_full_shutdown ( void ); 50 int eb_pxenv_get_cached_info (uint8_t, void **info); 51 52 /************************************************************************** 53 * Utility functions 54 **************************************************************************/ 55 56 /* Checksum a block. 57 */ 58 59 uint8_t checksum ( void *block, size_t size ) { 60 uint8_t sum = 0; 61 uint16_t i = 0; 62 for ( i = 0; i < size; i++ ) { 63 sum += ( ( uint8_t * ) block )[i]; 64 } 65 return sum; 66 } 67 68 /* Print the status of a !PXE structure 69 */ 70 71 void pxe_dump ( void ) { 72 #ifdef TRACE_UNDI 73 printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx " 74 "BD %hx:%hx BC %hx:%hx\n", 75 undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset, 76 undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size, 77 undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size, 78 undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size, 79 undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size, 80 undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size ); 81 #endif 82 } 83 84 /* Allocate/free space for structures that must reside in base memory 85 */ 86 87 int allocate_base_mem_data ( void ) { 88 /* In GRUB, anything is in base address, so we do not need 89 * allocate anything */ 90 undi.base_mem_data = &undi_base_mem_data; 91 memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 92 undi.undi_call_info = &undi.base_mem_data->undi_call_info; 93 undi.pxs = &undi.base_mem_data->pxs; 94 undi.xmit_data = &undi.base_mem_data->xmit_data; 95 undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 96 #if 0 /* Etherboot Code */ 97 /* Allocate space in base memory. 98 * Initialise pointers to base memory structures. 99 */ 100 if ( undi.base_mem_data == NULL ) { 101 undi.base_mem_data = 102 allot_base_memory ( sizeof(undi_base_mem_data_t) + 103 TRIVIAL_IRQ_HANDLER_SIZE ); 104 if ( undi.base_mem_data == NULL ) { 105 printf ( "Failed to allocate base memory\n" ); 106 free_base_mem_data(); 107 return 0; 108 } 109 memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 110 undi.undi_call_info = &undi.base_mem_data->undi_call_info; 111 undi.pxs = &undi.base_mem_data->pxs; 112 undi.xmit_data = &undi.base_mem_data->xmit_data; 113 undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 114 copy_trivial_irq_handler ( undi.base_mem_data->irq_handler, 115 TRIVIAL_IRQ_HANDLER_SIZE ); 116 } 117 #endif /* Etherboot Code */ 118 return 1; 119 } 120 121 int free_base_mem_data ( void ) { 122 /* Just pretend to free something :-) */ 123 undi.base_mem_data = NULL; 124 undi.undi_call_info = NULL; 125 undi.pxs = NULL; 126 undi.xmit_data = NULL; 127 undi.xmit_buffer = NULL; 128 #if 0 /* Etherboot Code */ 129 if ( undi.base_mem_data != NULL ) { 130 forget_base_memory ( undi.base_mem_data, 131 sizeof(undi_base_mem_data_t) + 132 TRIVIAL_IRQ_HANDLER_SIZE ); 133 undi.base_mem_data = NULL; 134 undi.undi_call_info = NULL; 135 undi.pxs = NULL; 136 undi.xmit_data = NULL; 137 undi.xmit_buffer = NULL; 138 copy_trivial_irq_handler ( NULL, 0 ); 139 } 140 #endif /* Etherboot Code */ 141 return 1; 142 } 143 144 void assemble_firing_squad ( firing_squad_lineup_t *lineup, 145 void *start, size_t size, 146 firing_squad_shoot_t shoot ) { 147 int target; 148 int index; 149 int bit; 150 int start_kb = virt_to_phys(start) >> 10; 151 int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10; 152 153 for ( target = start_kb; target <= end_kb; target++ ) { 154 index = FIRING_SQUAD_TARGET_INDEX ( target ); 155 bit = FIRING_SQUAD_TARGET_BIT ( target ); 156 lineup->targets[index] = ( shoot << bit ) | 157 ( lineup->targets[index] & ~( 1 << bit ) ); 158 } 159 } 160 161 void shoot_targets ( firing_squad_lineup_t *lineup ) { 162 int shoot_this_target = 0; 163 int shoot_last_target = 0; 164 int start_target = 0; 165 int target; 166 167 for ( target = 0; target <= 640; target++ ) { 168 shoot_this_target = ( target == 640 ? 0 : 169 ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) & 170 lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] ); 171 if ( shoot_this_target && !shoot_last_target ) { 172 start_target = target; 173 } else if ( shoot_last_target && !shoot_this_target ) { 174 size_t range_size = ( target - start_target ) << 10; 175 forget_base_memory ( phys_to_virt( start_target<<10 ), 176 range_size ); 177 } 178 shoot_last_target = shoot_this_target; 179 } 180 } 181 182 /* Debug macros 183 */ 184 185 #ifdef TRACE_UNDI 186 #define DBG(...) printf ( __VA_ARGS__ ) 187 #else 188 #define DBG(...) 189 #endif 190 191 #define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \ 192 "SUCCESS" : \ 193 ( (pxs)->Status == PXENV_EXIT_FAILURE ? \ 194 "FAILURE" : "UNKNOWN" ) ) 195 196 /************************************************************************** 197 * Base memory scanning functions 198 **************************************************************************/ 199 200 /* Locate the $PnP structure indicating a PnP BIOS. 201 */ 202 203 int hunt_pnp_bios ( void ) { 204 uint32_t off = 0x10000; 205 206 DBG ( "Hunting for PnP BIOS..." ); 207 while ( off > 0 ) { 208 off -= 16; 209 undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off ); 210 if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) { 211 DBG ( "found $PnP at f000:%hx...", off ); 212 if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) { 213 DBG ( "invalid checksum\n..." ); 214 continue; 215 } 216 DBG ( "ok\n" ); 217 return 1; 218 } 219 } 220 DBG ( "none found\n" ); 221 undi.pnp_bios = NULL; 222 return 0; 223 } 224 225 /* Locate the !PXE structure indicating a loaded UNDI driver. 226 */ 227 228 int hunt_pixie ( void ) { 229 static uint32_t ptr = 0; 230 pxe_t *pxe = NULL; 231 232 DBG ( "Hunting for pixies..." ); 233 if ( ptr == 0 ) ptr = 0xa0000; 234 while ( ptr > 0x10000 ) { 235 ptr -= 16; 236 pxe = (pxe_t *) phys_to_virt ( ptr ); 237 if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) { 238 DBG ( "found !PXE at %x...", ptr ); 239 if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 240 DBG ( "invalid checksum\n..." ); 241 continue; 242 } 243 if ( ptr < get_free_base_memory() ) { 244 DBG ( "in free base memory!\n\n" 245 "WARNING: a valid !PXE structure was " 246 "found in an area of memory marked " 247 "as free!\n\n" ); 248 undi.pxe = pxe; 249 pxe_dump(); 250 undi.pxe = NULL; 251 DBG ( "\nIgnoring and continuing, but this " 252 "may cause problems later!\n\n" ); 253 continue; 254 } 255 DBG ( "ok\n" ); 256 undi.pxe = pxe; 257 pxe_dump(); 258 DBG ( "Resetting pixie...\n" ); 259 undi_unload_base_code(); 260 eb_pxenv_stop_undi(); 261 pxe_dump(); 262 return 1; 263 } 264 } 265 DBG ( "none found\n" ); 266 ptr = 0; 267 return 0; 268 } 269 270 /* Locate PCI PnP ROMs. 271 */ 272 273 int hunt_rom ( void ) { 274 static uint32_t ptr = 0; 275 276 DBG ( "Hunting for ROMs..." ); 277 if ( ptr == 0 ) ptr = 0x100000; 278 while ( ptr > 0x0c0000 ) { 279 ptr -= 0x800; 280 undi.rom = ( rom_t * ) phys_to_virt ( ptr ); 281 if ( undi.rom->signature == ROM_SIGNATURE ) { 282 pcir_header_t *pcir_header = NULL; 283 pnp_header_t *pnp_header = NULL; 284 285 DBG ( "found 55AA at %x...", ptr ); 286 if ( undi.rom->pcir_off == 0 ) { 287 DBG ( "not a PCI ROM\n..." ); 288 continue; 289 } 290 pcir_header = (pcir_header_t*)( ( void * ) undi.rom + 291 undi.rom->pcir_off ); 292 if ( pcir_header->signature != PCIR_SIGNATURE ) { 293 DBG ( "invalid PCI signature\n..." ); 294 continue; 295 } 296 DBG ( "PCI:%hx:%hx...", pcir_header->vendor_id, 297 pcir_header->device_id ); 298 if ( ( pcir_header->vendor_id != undi.pci.vendor ) || 299 ( pcir_header->device_id != undi.pci.dev_id ) ) { 300 DBG ( "not me (%hx:%hx)\n...", 301 undi.pci.vendor, 302 undi.pci.dev_id ); 303 continue; 304 } 305 if ( undi.rom->pnp_off == 0 ) { 306 DBG ( "not a PnP ROM\n..." ); 307 continue; 308 } 309 pnp_header = (pnp_header_t*)( ( void * ) undi.rom + 310 undi.rom->pnp_off ); 311 if ( pnp_header->signature != PNP_SIGNATURE ) { 312 DBG ( "invalid $PnP signature\n..." ); 313 continue; 314 } 315 if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) { 316 DBG ( "invalid PnP checksum\n..." ); 317 continue; 318 } 319 DBG ( "ok\n"); 320 printf ("ROM %s by %s\n", 321 pnp_header->product_str_off==0 ? "(unknown)" : 322 (void*)undi.rom+pnp_header->product_str_off, 323 pnp_header->manuf_str_off==0 ? "(unknown)" : 324 (void*)undi.rom+pnp_header->manuf_str_off ); 325 return 1; 326 } 327 } 328 DBG ( "none found\n" ); 329 ptr = 0; 330 undi.rom = NULL; 331 return 0; 332 } 333 334 /* Locate ROMs containing UNDI drivers. 335 */ 336 337 int hunt_undi_rom ( void ) { 338 while ( hunt_rom() ) { 339 if ( undi.rom->undi_rom_id_off == 0 ) { 340 DBG ( "Not a PXE ROM\n" ); 341 continue; 342 } 343 undi.undi_rom_id = (undi_rom_id_t *) 344 ( (void *)undi.rom + undi.rom->undi_rom_id_off ); 345 if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) { 346 DBG ( "Invalid UNDI signature\n" ); 347 continue; 348 } 349 printf ( "Revision %d.%d.%d", 350 undi.undi_rom_id->undi_rev[2], 351 undi.undi_rom_id->undi_rev[1], 352 undi.undi_rom_id->undi_rev[0] ); 353 return 1; 354 } 355 return 0; 356 } 357 358 /************************************************************************** 359 * Low-level UNDI API call wrappers 360 **************************************************************************/ 361 362 /* Make a real-mode UNDI API call to the UNDI routine at 363 * routine_seg:routine_off, passing in three uint16 parameters on the 364 * real-mode stack. 365 * Calls the assembler wrapper routine __undi_call. 366 */ 367 368 static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg, 369 uint16_t routine_off, uint16_t st0, 370 uint16_t st1, uint16_t st2 ) { 371 PXENV_EXIT_t ret = PXENV_EXIT_FAILURE; 372 373 undi.undi_call_info->routine.segment = routine_seg; 374 undi.undi_call_info->routine.offset = routine_off; 375 undi.undi_call_info->stack[0] = st0; 376 undi.undi_call_info->stack[1] = st1; 377 undi.undi_call_info->stack[2] = st2; 378 ret = __undi_call ( SEGMENT( undi.undi_call_info ), 379 OFFSET( undi.undi_call_info ) ); 380 381 /* UNDI API calls may rudely change the status of A20 and not 382 * bother to restore it afterwards. Intel is known to be 383 * guilty of this. 384 * 385 * Note that we will return to this point even if A20 gets 386 * screwed up by the UNDI driver, because Etherboot always 387 * resides in an even megabyte of RAM. 388 */ 389 gateA20_set(); 390 391 return ret; 392 } 393 394 /* Make a real-mode call to the UNDI loader routine at 395 * routine_seg:routine_off, passing in the seg:off address of a 396 * pxenv_structure on the real-mode stack. 397 */ 398 399 int undi_call_loader ( void ) { 400 PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 401 402 pxenv_exit = _undi_call ( SEGMENT( undi.rom ), 403 undi.undi_rom_id->undi_loader_off, 404 OFFSET( undi.pxs ), 405 SEGMENT( undi.pxs ), 406 0 /* Unused for UNDI loader API */ ); 407 /* Return 1 for success, to be consistent with other routines */ 408 if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1; 409 DBG ( "UNDI loader call failed with status %#hx\n", 410 undi.pxs->Status ); 411 return 0; 412 } 413 414 /* Make a real-mode UNDI API call, passing in the opcode and the 415 * seg:off address of a pxenv_structure on the real-mode stack. 416 * 417 * Two versions: undi_call() will automatically report any failure 418 * codes, undi_call_silent() will not. 419 */ 420 421 int undi_call_silent ( uint16_t opcode ) { 422 PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 423 424 pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment, 425 undi.pxe->EntryPointSP.offset, 426 opcode, 427 OFFSET( undi.pxs ), 428 SEGMENT( undi.pxs ) ); 429 /* Return 1 for success, to be consistent with other routines */ 430 return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0; 431 } 432 433 int undi_call ( uint16_t opcode ) { 434 if ( undi_call_silent ( opcode ) ) return 1; 435 DBG ( "UNDI API call %#hx failed with status %#hx\n", 436 opcode, undi.pxs->Status ); 437 return 0; 438 } 439 440 /************************************************************************** 441 * High-level UNDI API call wrappers 442 **************************************************************************/ 443 444 /* Install the UNDI driver from a located UNDI ROM. 445 */ 446 447 int undi_loader ( void ) { 448 pxe_t *pxe = NULL; 449 450 /* AX contains PCI bus:devfn (PCI specification) */ 451 undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 452 /* BX and DX set to 0xffff for non-ISAPnP devices 453 * (BIOS boot specification) 454 */ 455 undi.pxs->loader.bx = 0xffff; 456 undi.pxs->loader.dx = 0xffff; 457 /* ES:DI points to PnP BIOS' $PnP structure 458 * (BIOS boot specification) 459 */ 460 undi.pxs->loader.es = 0xf000; 461 undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 462 463 /* Allocate space for UNDI driver's code and data segments */ 464 undi.driver_code_size = undi.undi_rom_id->code_size; 465 undi.driver_code = UNDI_HEAP; 466 if ( undi.driver_code == NULL ) { 467 printf ( "Could not allocate %d bytes for UNDI code segment\n", 468 undi.driver_code_size ); 469 return 0; 470 } 471 undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code ); 472 473 undi.driver_data_size = undi.undi_rom_id->data_size; 474 undi.driver_data = (void *)((((unsigned long)UNDI_HEAP + undi.undi_rom_id->code_size) | (1024 -1)) + 1); 475 if ( undi.driver_data == NULL ) { 476 printf ( "Could not allocate %d bytes for UNDI code segment\n", 477 undi.driver_data_size ); 478 return 0; 479 } 480 undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data ); 481 482 DBG ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n", 483 undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds ); 484 485 /* Do the API call to install the loader */ 486 if ( ! undi_call_loader () ) return 0; 487 488 pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 489 DBG ( "UNDI driver created a pixie at %hx:%hx...", 490 undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 491 if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) { 492 DBG ( "invalid signature\n" ); 493 return 0; 494 } 495 if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 496 DBG ( "invalid checksum\n" ); 497 return 0; 498 } 499 DBG ( "ok\n" ); 500 undi.pxe = pxe; 501 pxe_dump(); 502 return 1; 503 } 504 505 /* Start the UNDI driver. 506 */ 507 508 int eb_pxenv_start_undi ( void ) { 509 int success = 0; 510 511 /* AX contains PCI bus:devfn (PCI specification) */ 512 undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 513 /* BX and DX set to 0xffff for non-ISAPnP devices 514 * (BIOS boot specification) 515 */ 516 undi.pxs->start_undi.bx = 0xffff; 517 undi.pxs->start_undi.dx = 0xffff; 518 /* ES:DI points to PnP BIOS' $PnP structure 519 * (BIOS boot specification) 520 */ 521 undi.pxs->start_undi.es = 0xf000; 522 undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 523 524 DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n", 525 undi.pxs->start_undi.ax, 526 undi.pxs->start_undi.bx, undi.pxs->start_undi.dx, 527 undi.pxs->start_undi.es, undi.pxs->start_undi.di ); 528 success = undi_call ( PXENV_START_UNDI ); 529 DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 530 if ( success ) undi.prestarted = 1; 531 return success; 532 } 533 534 int eb_pxenv_undi_startup ( void ) { 535 int success = 0; 536 537 DBG ( "PXENV_UNDI_STARTUP => (void)\n" ); 538 success = undi_call ( PXENV_UNDI_STARTUP ); 539 DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 540 if ( success ) undi.started = 1; 541 return success; 542 } 543 544 int eb_pxenv_undi_cleanup ( void ) { 545 int success = 0; 546 547 DBG ( "PXENV_UNDI_CLEANUP => (void)\n" ); 548 success = undi_call ( PXENV_UNDI_CLEANUP ); 549 DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 550 return success; 551 } 552 553 int eb_pxenv_undi_initialize ( void ) { 554 int success = 0; 555 556 undi.pxs->undi_initialize.ProtocolIni = 0; 557 memset ( &undi.pxs->undi_initialize.reserved, 0, 558 sizeof ( undi.pxs->undi_initialize.reserved ) ); 559 DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" ); 560 success = undi_call ( PXENV_UNDI_INITIALIZE ); 561 DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 562 if ( success ) undi.initialized = 1; 563 return success; 564 } 565 566 int eb_pxenv_undi_shutdown ( void ) { 567 int success = 0; 568 569 DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" ); 570 success = undi_call ( PXENV_UNDI_SHUTDOWN ); 571 DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 572 if ( success ) { 573 undi.initialized = 0; 574 undi.started = 0; 575 } 576 return success; 577 } 578 579 int eb_pxenv_undi_open ( void ) { 580 int success = 0; 581 582 undi.pxs->undi_open.OpenFlag = 0; 583 undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST; 584 585 /* Multicast support not yet implemented */ 586 undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0; 587 DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx " 588 "MCastAddrCount=%hx\n", 589 undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter, 590 undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount ); 591 success = undi_call ( PXENV_UNDI_OPEN ); 592 DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 593 if ( success ) undi.opened = 1; 594 return success; 595 } 596 597 int eb_pxenv_undi_close ( void ) { 598 int success = 0; 599 600 DBG ( "PXENV_UNDI_CLOSE => (void)\n" ); 601 success = undi_call ( PXENV_UNDI_CLOSE ); 602 DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 603 if ( success ) undi.opened = 0; 604 return success; 605 } 606 607 int eb_pxenv_undi_transmit_packet ( void ) { 608 int success = 0; 609 static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; 610 611 /* XMitFlag selects unicast / broadcast */ 612 if ( memcmp ( undi.xmit_data->destaddr, broadcast, 613 sizeof(broadcast) ) == 0 ) { 614 undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST; 615 } else { 616 undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR; 617 } 618 619 /* Zero reserved dwords */ 620 undi.pxs->undi_transmit.Reserved[0] = 0; 621 undi.pxs->undi_transmit.Reserved[1] = 0; 622 623 /* Segment:offset pointer to DestAddr in base memory */ 624 undi.pxs->undi_transmit.DestAddr.segment = 625 SEGMENT( undi.xmit_data->destaddr ); 626 undi.pxs->undi_transmit.DestAddr.offset = 627 OFFSET( undi.xmit_data->destaddr ); 628 629 /* Segment:offset pointer to TBD in base memory */ 630 undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd ); 631 undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd ); 632 633 /* Use only the "immediate" part of the TBD */ 634 undi.xmit_data->tbd.DataBlkCount = 0; 635 636 DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n" 637 "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n", 638 undi.pxs->undi_transmit.Protocol, 639 undi.pxs->undi_transmit.XmitFlag, 640 undi.pxs->undi_transmit.DestAddr.segment, 641 undi.pxs->undi_transmit.DestAddr.offset, 642 undi.pxs->undi_transmit.TBD.segment, 643 undi.pxs->undi_transmit.TBD.offset ); 644 DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n", 645 undi.xmit_data->tbd.ImmedLength, 646 undi.xmit_data->tbd.Xmit.segment, 647 undi.xmit_data->tbd.Xmit.offset, 648 undi.xmit_data->tbd.DataBlkCount ); 649 success = undi_call ( PXENV_UNDI_TRANSMIT ); 650 DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n", 651 UNDI_STATUS(undi.pxs) ); 652 return success; 653 } 654 655 int eb_pxenv_undi_set_station_address ( void ) { 656 /* This will spuriously fail on some cards. Ignore failures. 657 * We only ever use it to set the MAC address to the card's 658 * permanent value anyway, so it's a useless call (although we 659 * make it because PXE spec says we should). 660 */ 661 DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => " 662 "StationAddress=%!\n", 663 undi.pxs->undi_set_station_address.StationAddress ); 664 undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS ); 665 DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n", 666 UNDI_STATUS(undi.pxs) ); 667 return 1; 668 } 669 670 int eb_pxenv_undi_get_information ( void ) { 671 int success = 0; 672 memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 673 DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" ); 674 success = undi_call ( PXENV_UNDI_GET_INFORMATION ); 675 DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s " 676 "BaseIO=%hx IntNumber=%hx ...\n" 677 "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n" 678 "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n" 679 "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n", 680 UNDI_STATUS(undi.pxs), 681 undi.pxs->undi_get_information.BaseIo, 682 undi.pxs->undi_get_information.IntNumber, 683 undi.pxs->undi_get_information.MaxTranUnit, 684 undi.pxs->undi_get_information.HwType, 685 undi.pxs->undi_get_information.HwAddrLen, 686 undi.pxs->undi_get_information.CurrentNodeAddress, 687 undi.pxs->undi_get_information.PermNodeAddress, 688 undi.pxs->undi_get_information.ROMAddress, 689 undi.pxs->undi_get_information.RxBufCt, 690 undi.pxs->undi_get_information.TxBufCt ); 691 return success; 692 } 693 694 int eb_pxenv_undi_get_iface_info ( void ) { 695 int success = 0; 696 697 DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" ); 698 success = undi_call ( PXENV_UNDI_GET_IFACE_INFO ); 699 DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n" 700 "... LinkSpeed=%x ServiceFlags=%x\n", 701 UNDI_STATUS(undi.pxs), 702 undi.pxs->undi_get_iface_info.IfaceType, 703 undi.pxs->undi_get_iface_info.LinkSpeed, 704 undi.pxs->undi_get_iface_info.ServiceFlags ); 705 return success; 706 } 707 708 int eb_pxenv_undi_isr ( void ) { 709 int success = 0; 710 711 DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n", 712 undi.pxs->undi_isr.FuncFlag ); 713 success = undi_call ( PXENV_UNDI_ISR ); 714 DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n" 715 "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx " 716 "ProtType=%hhx ...\n... PktType=%hhx\n", 717 UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag, 718 undi.pxs->undi_isr.BufferLength, 719 undi.pxs->undi_isr.FrameLength, 720 undi.pxs->undi_isr.FrameHeaderLength, 721 undi.pxs->undi_isr.Frame.segment, 722 undi.pxs->undi_isr.Frame.offset, 723 undi.pxs->undi_isr.ProtType, 724 undi.pxs->undi_isr.PktType ); 725 return success; 726 } 727 728 int eb_pxenv_stop_undi ( void ) { 729 int success = 0; 730 731 DBG ( "PXENV_STOP_UNDI => (void)\n" ); 732 success = undi_call ( PXENV_STOP_UNDI ); 733 DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 734 if ( success ) undi.prestarted = 0; 735 return success; 736 } 737 738 int eb_pxenv_unload_stack ( void ) { 739 int success = 0; 740 741 memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 742 DBG ( "PXENV_UNLOAD_STACK => (void)\n" ); 743 success = undi_call_silent ( PXENV_UNLOAD_STACK ); 744 DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n", 745 UNDI_STATUS(undi.pxs), 746 ( undi.pxs->Status == PXENV_STATUS_SUCCESS ? 747 "base-code is ready to be removed" : 748 ( undi.pxs->Status == PXENV_STATUS_FAILURE ? 749 "the size of free base memory has been changed" : 750 ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ? 751 "the NIC interrupt vector has been changed" : 752 "UNEXPECTED STATUS CODE" ) ) ) ); 753 return success; 754 } 755 756 int eb_pxenv_stop_base ( void ) { 757 int success = 0; 758 759 DBG ( "PXENV_STOP_BASE => (void)\n" ); 760 success = undi_call ( PXENV_STOP_BASE ); 761 DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 762 return success; 763 } 764 765 /* Unload UNDI base code (if any present) and free memory. 766 */ 767 int undi_unload_base_code ( void ) { 768 /* In GRUB, we do not allocate anything, but we still can call 769 * to free the base space */ 770 void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 ); 771 size_t bc_code_size = undi.pxe->BC_Code.Seg_Size; 772 void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 ); 773 size_t bc_data_size = undi.pxe->BC_Data.Seg_Size; 774 void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 ); 775 size_t bc_stck_size = undi.pxe->Stack.Seg_Size; 776 firing_squad_lineup_t lineup; 777 778 /* Don't unload if there is no base code present */ 779 if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1; 780 781 /* Since we never start the base code, the only time we should 782 * reach this is if we were loaded via PXE. There are many 783 * different and conflicting versions of the "correct" way to 784 * unload the PXE base code, several of which appear within 785 * the PXE specification itself. This one seems to work for 786 * our purposes. 787 */ 788 eb_pxenv_stop_base(); 789 //eb_pxenv_unload_stack(); 790 /* if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) && 791 ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) { 792 printf ( "Could not free memory allocated to PXE base code: " 793 "possible memory leak\n" ); 794 return 0; 795 }*/ 796 /* Free data structures. Forget what the PXE specification 797 * says about how to calculate the new size of base memory; 798 * basemem.c takes care of all that for us. Note that we also 799 * have to free the stack (even though PXE spec doesn't say 800 * anything about it) because nothing else is going to do so. 801 * 802 * Structures will almost certainly not be kB-aligned and 803 * there's a reasonable chance that the UNDI code or data 804 * portions will lie in the same kB as the base code. Since 805 * forget_base_memory works only in 1kB increments, this means 806 * we have to do some arcane trickery. 807 */ 808 memset ( &lineup, 0, sizeof(lineup) ); 809 if ( SEGMENT(bc_code) != 0 ) 810 assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT ); 811 if ( SEGMENT(bc_data) != 0 ) 812 assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT ); 813 if ( SEGMENT(bc_stck) != 0 ) 814 assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT ); 815 /* Don't shoot any bits of the UNDI driver code or data */ 816 assemble_firing_squad ( &lineup, 817 VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0), 818 undi.pxe->UNDICode.Seg_Size, DONTSHOOT ); 819 assemble_firing_squad ( &lineup, 820 VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0), 821 undi.pxe->UNDIData.Seg_Size, DONTSHOOT ); 822 //shoot_targets ( &lineup ); 823 //undi.pxe->BC_Code.Seg_Addr = 0; 824 //undi.pxe->BC_Data.Seg_Addr = 0; 825 //undi.pxe->Stack.Seg_Addr = 0; 826 827 /* Free and reallocate our own base memory data structures, to 828 * allow the freed base-code blocks to be fully released. 829 */ 830 free_base_mem_data(); 831 if ( ! allocate_base_mem_data() ) { 832 printf ( "FATAL: memory unaccountably lost\n" ); 833 while ( 1 ) {}; 834 } 835 836 return 1; 837 } 838 839 /* UNDI full initialization 840 * 841 * This calls all the various UNDI initialization routines in sequence. 842 */ 843 844 int undi_full_startup ( void ) { 845 if ( ! eb_pxenv_start_undi() ) return 0; 846 if ( ! eb_pxenv_undi_startup() ) return 0; 847 if ( ! eb_pxenv_undi_initialize() ) return 0; 848 if ( ! eb_pxenv_undi_get_information() ) return 0; 849 undi.irq = undi.pxs->undi_get_information.IntNumber; 850 if ( ! install_undi_irq_handler ( undi.irq, undi.pxe->EntryPointSP ) ) { 851 undi.irq = IRQ_NONE; 852 return 0; 853 } 854 memmove ( &undi.pxs->undi_set_station_address.StationAddress, 855 &undi.pxs->undi_get_information.PermNodeAddress, 856 sizeof (undi.pxs->undi_set_station_address.StationAddress) ); 857 if ( ! eb_pxenv_undi_set_station_address() ) return 0; 858 if ( ! eb_pxenv_undi_open() ) return 0; 859 /* install_undi_irq_handler leaves irq disabled */ 860 enable_irq ( undi.irq ); 861 return 1; 862 } 863 864 /* UNDI full shutdown 865 * 866 * This calls all the various UNDI shutdown routines in sequence and 867 * also frees any memory that it can. 868 */ 869 870 int undi_full_shutdown ( void ) { 871 if ( undi.pxe != NULL ) { 872 /* In case we didn't allocate the driver's memory in the first 873 * place, try to grab the code and data segments and sizes 874 * from the !PXE structure. 875 */ 876 if ( undi.driver_code == NULL ) { 877 undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 878 0 ); 879 undi.driver_code_size = undi.pxe->UNDICode.Seg_Size; 880 } 881 if ( undi.driver_data == NULL ) { 882 undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 883 0 ); 884 undi.driver_data_size = undi.pxe->UNDIData.Seg_Size; 885 } 886 887 /* Ignore errors and continue in the hope of shutting 888 * down anyway 889 */ 890 if ( undi.opened ) eb_pxenv_undi_close(); 891 if ( undi.started ) { 892 eb_pxenv_undi_cleanup(); 893 /* We may get spurious UNDI API errors at this 894 * point. If startup() succeeded but 895 * initialize() failed then according to the 896 * spec, we should call shutdown(). However, 897 * some NICS will fail with a status code 898 * 0x006a (INVALID_STATE). 899 */ 900 eb_pxenv_undi_shutdown(); 901 } 902 if ( undi.irq != IRQ_NONE ) { 903 remove_undi_irq_handler ( undi.irq ); 904 undi.irq = IRQ_NONE; 905 } 906 undi_unload_base_code(); 907 if ( undi.prestarted ) { 908 eb_pxenv_stop_undi(); 909 /* Success OR Failure indicates that memory 910 * can be freed. Any other status code means 911 * that it can't. 912 */ 913 if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) || 914 ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) { 915 printf ("Could not free memory allocated to " 916 "UNDI driver: possible memory leak\n"); 917 return 0; 918 } 919 } 920 } 921 /* Free memory allocated to UNDI driver */ 922 if ( undi.driver_code != NULL ) { 923 /* Clear contents in order to eliminate !PXE and PXENV 924 * signatures to prevent spurious detection via base 925 * memory scan. 926 */ 927 memset ( undi.driver_code, 0, undi.driver_code_size ); 928 /* forget_base_memory ( undi.driver_code, undi.driver_code_size ); */ 929 undi.driver_code = NULL; 930 undi.driver_code_size = 0; 931 } 932 if ( undi.driver_data != NULL ) { 933 /* forget_base_memory ( undi.driver_data, undi.driver_data_size ); */ 934 undi.driver_data = NULL; 935 undi.driver_data_size = 0; 936 } 937 /* !PXE structure now gone; memory freed */ 938 undi.pxe = NULL; 939 return 1; 940 } 941 942 /************************************************************************** 943 POLL - Wait for a frame 944 ***************************************************************************/ 945 static int undi_poll(struct nic *nic, int retrieve) 946 { 947 /* Fun, fun, fun. UNDI drivers don't use polling; they use 948 * interrupts. We therefore cheat and pretend that an 949 * interrupt has occurred every time undi_poll() is called. 950 * This isn't too much of a hack; PCI devices share IRQs and 951 * so the first thing that a proper ISR should do is call 952 * PXENV_UNDI_ISR to determine whether or not the UNDI NIC 953 * generated the interrupt; there is no harm done by spurious 954 * calls to PXENV_UNDI_ISR. Similarly, we wouldn't be 955 * handling them any more rapidly than the usual rate of 956 * undi_poll() being called even if we did implement a full 957 * ISR. So it should work. Ha! 958 * 959 * Addendum (21/10/03). Some cards don't play nicely with 960 * this trick, so instead of doing it the easy way we have to 961 * go to all the hassle of installing a genuine interrupt 962 * service routine and dealing with the wonderful 8259 963 * Programmable Interrupt Controller. Joy. 964 * 965 * (02/01/2005). A real UNDI ISR is now implemented in, 966 * following Figure 3-4 in PXE spec 2.0. The interrupt 967 * handler, undi_irq_handler, issues PXENV_UNDI_ISR_IN_START. 968 * If the interrupt is ours, the handler sends EOI and bumps the 969 * undi_irq_trigger_count. This polled routine is equivalent 970 * to the "driver strategy routine". 971 * 972 * Another issue is that upper layer await_*() does not handle 973 * coalesced packets. The UNDI implementation on broadcom chips 974 * appear to combine interrupts. If we loop through GET_NEXT, 975 * we may hand up coalesced packets, resulting in drops, and 976 * severe time delay. As a temperary hack, we return as soon as 977 * we get something, remembering where we were (IN_PROCESS 978 * or GET_NEXT). This assume packets are never broken up. 979 * XXX Need to fix upper layer to handle coalesced data. 980 */ 981 982 static int undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 983 984 /* See if a hardware interrupt has occurred since the last poll(). 985 */ 986 switch ( undi_opcode ) { 987 case PXENV_UNDI_ISR_IN_PROCESS: 988 if ( ! undi_irq_triggered ( undi.irq ) ) 989 return 0; 990 default: 991 break; 992 } 993 994 /* We have an interrupt or there is something left from 995 * last poll. Either way, we need to call UNDI ISR. 996 */ 997 nic->packetlen = 0; 998 undi.pxs->undi_isr.FuncFlag = undi_opcode; 999 /* there is no good way to handle this error */ 1000 if ( ! eb_pxenv_undi_isr() ) { 1001 printf ("undi isr call failed: opcode = %d\n", undi_opcode); 1002 return 0; 1003 } 1004 switch ( undi.pxs->undi_isr.FuncFlag ) { 1005 case PXENV_UNDI_ISR_OUT_DONE: 1006 /* Set opcode back to IN_PROCESS and wait for next intr */ 1007 undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 1008 return 0; 1009 case PXENV_UNDI_ISR_OUT_TRANSMIT: 1010 /* We really don't care about transmission complete 1011 * interrupts. Move on to next frame. 1012 */ 1013 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1014 return 0; 1015 case PXENV_UNDI_ISR_OUT_BUSY: 1016 /* This should never happen. 1017 */ 1018 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1019 printf ( "UNDI ISR thinks it's being re-entered!\n" 1020 "Aborting receive\n" ); 1021 return 0; 1022 case PXENV_UNDI_ISR_OUT_RECEIVE: 1023 /* Copy data to receive buffer and move on to next frame */ 1024 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1025 memcpy ( nic->packet + nic->packetlen, 1026 VIRTUAL( undi.pxs->undi_isr.Frame.segment, 1027 undi.pxs->undi_isr.Frame.offset ), 1028 undi.pxs->undi_isr.BufferLength ); 1029 nic->packetlen += undi.pxs->undi_isr.BufferLength; 1030 break; 1031 default: 1032 undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 1033 printf ( "UNDI ISR returned bizzare status code %d\n", 1034 undi.pxs->undi_isr.FuncFlag ); 1035 } 1036 1037 return nic->packetlen > 0 ? 1 : 0; 1038 } 1039 1040 /************************************************************************** 1041 TRANSMIT - Transmit a frame 1042 ***************************************************************************/ 1043 static void undi_transmit( 1044 struct nic *nic, 1045 const char *d, /* Destination */ 1046 unsigned int t, /* Type */ 1047 unsigned int s, /* size */ 1048 const char *p) /* Packet */ 1049 { 1050 /* Inhibit compiler warning about unused parameter nic */ 1051 if ( nic == NULL ) {}; 1052 1053 /* Copy destination to buffer in base memory */ 1054 memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) ); 1055 1056 /* Translate packet type to UNDI packet type */ 1057 switch ( t ) { 1058 case IP : undi.pxs->undi_transmit.Protocol = P_IP; break; 1059 case ARP: undi.pxs->undi_transmit.Protocol = P_ARP; break; 1060 case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break; 1061 default: undi.pxs->undi_transmit.Protocol = P_UNKNOWN; break; 1062 } 1063 1064 /* Store packet length in TBD */ 1065 undi.xmit_data->tbd.ImmedLength = s; 1066 1067 /* Check to see if data to be transmitted is currently in base 1068 * memory. If not, allocate temporary storage in base memory 1069 * and copy it there. 1070 */ 1071 if ( SEGMENT( p ) <= 0xffff ) { 1072 undi.xmit_data->tbd.Xmit.segment = SEGMENT( p ); 1073 undi.xmit_data->tbd.Xmit.offset = OFFSET( p ); 1074 } else { 1075 memcpy ( undi.xmit_buffer, p, s ); 1076 undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer ); 1077 undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer ); 1078 } 1079 1080 eb_pxenv_undi_transmit_packet(); 1081 } 1082 1083 /************************************************************************** 1084 DISABLE - Turn off ethernet interface 1085 ***************************************************************************/ 1086 static void undi_disable(struct dev *dev) 1087 { 1088 /* Inhibit compiler warning about unused parameter dev */ 1089 if ( dev == NULL ) {}; 1090 undi_full_shutdown(); 1091 free_base_mem_data(); 1092 } 1093 1094 /************************************************************************** 1095 PROBE - Look for an adapter, this routine's visible to the outside 1096 ***************************************************************************/ 1097 1098 /* Locate an UNDI driver by first scanning through base memory for an 1099 * installed driver and then by scanning for UNDI ROMs and attempting 1100 * to install their drivers. 1101 */ 1102 1103 int hunt_pixies_and_undi_roms ( void ) { 1104 static uint8_t hunt_type = HUNT_FOR_PIXIES; 1105 1106 if ( hunt_type == HUNT_FOR_PIXIES ) { 1107 if ( hunt_pixie() ) { 1108 return 1; 1109 } 1110 } 1111 hunt_type = HUNT_FOR_UNDI_ROMS; 1112 while ( hunt_undi_rom() ) { 1113 if ( undi_loader() ) { 1114 return 1; 1115 } 1116 undi_full_shutdown(); /* Free any allocated memory */ 1117 } 1118 hunt_type = HUNT_FOR_PIXIES; 1119 return 0; 1120 } 1121 1122 /* The actual Etherboot probe routine. 1123 */ 1124 1125 static int undi_probe(struct dev *dev, struct pci_device *pci) 1126 { 1127 struct nic *nic = (struct nic *)dev; 1128 1129 /* Zero out global undi structure */ 1130 memset ( &undi, 0, sizeof(undi) ); 1131 1132 /* Store PCI parameters; we will need them to initialize the UNDI 1133 * driver later. 1134 */ 1135 memcpy ( &undi.pci, pci, sizeof(undi.pci) ); 1136 1137 /* Find the BIOS' $PnP structure */ 1138 if ( ! hunt_pnp_bios() ) { 1139 printf ( "No PnP BIOS found; aborting\n" ); 1140 return 0; 1141 } 1142 1143 /* Allocate base memory data structures */ 1144 if ( ! allocate_base_mem_data() ) return 0; 1145 1146 /* Search thoroughly for UNDI drivers */ 1147 for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) { 1148 /* Try to initialise UNDI driver */ 1149 DBG ( "Initializing UNDI driver. Please wait...\n" ); 1150 if ( ! undi_full_startup() ) { 1151 if ( undi.pxs->Status == 1152 PXENV_STATUS_UNDI_MEDIATEST_FAILED ) { 1153 DBG ( "Cable not connected (code %#hx)\n", 1154 PXENV_STATUS_UNDI_MEDIATEST_FAILED ); 1155 } 1156 continue; 1157 } 1158 /* Basic information: MAC, IO addr, IRQ */ 1159 if ( ! eb_pxenv_undi_get_information() ) continue; 1160 DBG ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n", 1161 undi.pxs->undi_get_information.BaseIo, 1162 undi.pxs->undi_get_information.IntNumber, 1163 undi.pxs->undi_get_information.CurrentNodeAddress ); 1164 /* Fill out MAC address in nic structure */ 1165 memcpy ( nic->node_addr, 1166 undi.pxs->undi_get_information.CurrentNodeAddress, 1167 ETH_ALEN ); 1168 /* More diagnostic information including link speed */ 1169 if ( ! eb_pxenv_undi_get_iface_info() ) continue; 1170 printf ( " NDIS type %s interface at %d Mbps\n", 1171 undi.pxs->undi_get_iface_info.IfaceType, 1172 undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 ); 1173 DBG ("UNDI Stack at %#hx:%#hx",UNDI_STACK_SEG, UNDI_STACK_OFF); 1174 dev->disable = undi_disable; 1175 nic->poll = undi_poll; 1176 nic->transmit = undi_transmit; 1177 return 1; 1178 } 1179 undi_disable ( dev ); /* To free base memory structures */ 1180 return 0; 1181 } 1182 1183 /* UNDI driver states that it is suitable for any PCI NIC (i.e. any 1184 * PCI device of class PCI_CLASS_NETWORK_ETHERNET). If there are any 1185 * obscure UNDI NICs that have the incorrect PCI class, add them to 1186 * this list. 1187 */ 1188 static struct pci_id undi_nics[] = { 1189 PCI_ROM(0x10de, 0x0057, "ck804", "nVidia Corporation CK804 Ethernet"), 1190 PCI_ROM(0x10de, 0x0373, "mcp55", "nVidia Corporation MCP55 Ethernet") 1191 }; 1192 1193 struct pci_driver undi_driver = { 1194 .type = NIC_DRIVER, 1195 .name = "UNDI", 1196 .probe = undi_probe, 1197 .ids = undi_nics, 1198 .id_count = sizeof(undi_nics)/sizeof(undi_nics[0]), 1199 .class = PCI_CLASS_NETWORK_ETHERNET, 1200 }; 1201 1202 /************************************************ 1203 * Code for reusing the BIOS provided pxe stack 1204 */ 1205 1206 /* Verify !PXE structure saved by pxeloader. */ 1207 int undi_bios_pxe(void **dhcpreply) 1208 { 1209 pxe_t *pxe; 1210 uint16_t *ptr = (uint16_t *)0x7C80; 1211 1212 pxe = (pxe_t *) VIRTUAL(ptr[0], ptr[1]); 1213 if (memcmp(pxe->Signature, "!PXE", 4) != 0) { 1214 DBG ("invalid !PXE signature at %x:%x\n", ptr[0], ptr[1]); 1215 return 0; 1216 } 1217 1218 if (checksum(pxe, sizeof(pxe_t)) != 0) { 1219 DBG ("invalid checksum\n"); 1220 return 0; 1221 } 1222 1223 /* Zero out global undi structure */ 1224 memset (&undi, 0, sizeof(undi)); 1225 1226 /* Allocate base memory data structures */ 1227 if (! allocate_base_mem_data()) return 0; 1228 1229 undi.pxe = pxe; 1230 pxe_dump(); 1231 1232 if (!eb_pxenv_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, dhcpreply)) { 1233 DBG ("failed to get cached DHCP reply\n"); 1234 return 0; 1235 } 1236 return 1; 1237 } 1238 1239 void undi_pxe_disable(void) 1240 { 1241 /* full shutdown is problematic for some machines */ 1242 (void) eb_pxenv_undi_shutdown(); 1243 } 1244 1245 /* 1246 * Various helper functions for dhcp and tftp 1247 */ 1248 int eb_pxenv_get_cached_info (uint8_t type, void **info) 1249 { 1250 int success; 1251 1252 memset(undi.pxs, 0, sizeof (undi.pxs)); 1253 /* Segment:offset pointer to DestAddr in base memory */ 1254 undi.pxs->get_cached_info.PacketType = type; 1255 undi.pxs->get_cached_info.BufferSize = 0; 1256 undi.pxs->get_cached_info.Buffer.segment = 0; 1257 undi.pxs->get_cached_info.Buffer.offset = 0; 1258 1259 success = undi_call(PXENV_GET_CACHED_INFO); 1260 DBG ("PXENV_GET_CACHED_INFO <= Status=%s\n", UNDI_STATUS(undi.pxs)); 1261 1262 *info = (void *)VIRTUAL(undi.pxs->get_cached_info.Buffer.segment, 1263 undi.pxs->get_cached_info.Buffer.offset); 1264 return success; 1265 } 1266 1267 /* tftp help routines */ 1268 int eb_pxenv_tftp_open(char *file, IP4_t serverip, IP4_t gatewayip, 1269 uint16_t *pktlen) 1270 { 1271 int success; 1272 memset(undi.pxs, 0, sizeof (undi.pxs)); 1273 undi.pxs->tftp_open.ServerIPAddress = serverip; 1274 undi.pxs->tftp_open.GatewayIPAddress = gatewayip; 1275 undi.pxs->tftp_open.TFTPPort = htons(TFTP_PORT); 1276 undi.pxs->tftp_open.PacketSize = TFTP_MAX_PACKET; 1277 (void) sprintf(undi.pxs->tftp_open.FileName, "%s", file); 1278 success = undi_call(PXENV_TFTP_OPEN); 1279 DBG ("PXENV_TFTP_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs)); 1280 *pktlen = undi.pxs->tftp_open.PacketSize; 1281 return success; 1282 } 1283 1284 int eb_pxenv_tftp_read(uint8_t *buf, uint16_t *len) 1285 { 1286 static int tftp_count = 0; 1287 1288 int success; 1289 memset(undi.pxs, 0, sizeof (undi.pxs)); 1290 undi.pxs->tftp_read.Buffer.segment = SEGMENT(buf); 1291 undi.pxs->tftp_read.Buffer.offset = OFFSET(buf); 1292 success = undi_call(PXENV_TFTP_READ); 1293 DBG ("PXENV_TFTP_READ <= Status=%s\n", UNDI_STATUS(undi.pxs)); 1294 *len = undi.pxs->tftp_read.BufferSize; 1295 tftp_count++; 1296 if ((tftp_count % 1000) == 0) 1297 noisy_printf("."); 1298 return success; 1299 } 1300 1301 int eb_pxenv_tftp_close(void) 1302 { 1303 int success; 1304 memset(undi.pxs, 0, sizeof (undi.pxs)); 1305 success = undi_call(PXENV_TFTP_CLOSE); 1306 DBG ("PXENV_TFTP_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs)); 1307 return success; 1308 } 1309 1310 int eb_pxenv_tftp_get_fsize(char *file, IP4_t serverip, IP4_t gatewayip, 1311 uint32_t *fsize) 1312 { 1313 int success; 1314 memset(undi.pxs, 0, sizeof (undi.pxs)); 1315 undi.pxs->tftp_open.ServerIPAddress = serverip; 1316 undi.pxs->tftp_open.GatewayIPAddress = gatewayip; 1317 (void) sprintf(undi.pxs->tftp_open.FileName, "%s", file); 1318 success = undi_call(PXENV_TFTP_GET_FSIZE); 1319 DBG ("PXENV_TFTP_GET_FSIZE <= Status=%s\n", UNDI_STATUS(undi.pxs)); 1320 *fsize = undi.pxs->tftp_get_fsize.FileSize; 1321 return success; 1322 } 1323