11b8adde7SWilliam Kucharski /************************************************************************** 21b8adde7SWilliam Kucharski Etherboot - BOOTP/TFTP Bootstrap Program 31b8adde7SWilliam Kucharski UNDI NIC driver for Etherboot 41b8adde7SWilliam Kucharski 51b8adde7SWilliam Kucharski This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk> 61b8adde7SWilliam Kucharski of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights 71b8adde7SWilliam Kucharski reserved. 81b8adde7SWilliam Kucharski 91b8adde7SWilliam Kucharski $Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $ 101b8adde7SWilliam Kucharski ***************************************************************************/ 111b8adde7SWilliam Kucharski 121b8adde7SWilliam Kucharski /* 131b8adde7SWilliam Kucharski * This program is free software; you can redistribute it and/or 141b8adde7SWilliam Kucharski * modify it under the terms of the GNU General Public License as 151b8adde7SWilliam Kucharski * published by the Free Software Foundation; either version 2, or (at 161b8adde7SWilliam Kucharski * your option) any later version. 171b8adde7SWilliam Kucharski */ 181b8adde7SWilliam Kucharski 191b8adde7SWilliam Kucharski /* to get some global routines like printf */ 201b8adde7SWilliam Kucharski #include "etherboot.h" 211b8adde7SWilliam Kucharski /* to get the interface to the body of the program */ 221b8adde7SWilliam Kucharski #include "nic.h" 231b8adde7SWilliam Kucharski /* to get the PCI support functions, if this is a PCI NIC */ 241b8adde7SWilliam Kucharski #include "pci.h" 251b8adde7SWilliam Kucharski /* UNDI and PXE defines. Includes pxe.h. */ 261b8adde7SWilliam Kucharski #include "undi.h" 271b8adde7SWilliam Kucharski /* 8259 PIC defines */ 281b8adde7SWilliam Kucharski #include "pic8259.h" 291b8adde7SWilliam Kucharski #include "bootp.h" 301b8adde7SWilliam Kucharski #include "tftp.h" 311b8adde7SWilliam Kucharski #include "shared.h" 321b8adde7SWilliam Kucharski 331b8adde7SWilliam Kucharski /* NIC specific static variables go here */ 341b8adde7SWilliam Kucharski static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 351b8adde7SWilliam Kucharski NULL, NULL, 0, NULL, 0, NULL, 361b8adde7SWilliam Kucharski 0, 0, 0, 0, 371b8adde7SWilliam Kucharski { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, NULL }, 381b8adde7SWilliam Kucharski IRQ_NONE }; 391b8adde7SWilliam Kucharski static undi_base_mem_data_t undi_base_mem_data; 401b8adde7SWilliam Kucharski 411b8adde7SWilliam Kucharski #define UNDI_HEAP (void *)(512 << 10) 421b8adde7SWilliam Kucharski 431b8adde7SWilliam Kucharski /* Function prototypes */ 441b8adde7SWilliam Kucharski int allocate_base_mem_data ( void ); 451b8adde7SWilliam Kucharski int free_base_mem_data ( void ); 461b8adde7SWilliam Kucharski int eb_pxenv_undi_shutdown ( void ); 471b8adde7SWilliam Kucharski int eb_pxenv_stop_undi ( void ); 481b8adde7SWilliam Kucharski int undi_unload_base_code ( void ); 491b8adde7SWilliam Kucharski int undi_full_shutdown ( void ); 501b8adde7SWilliam Kucharski int eb_pxenv_get_cached_info (uint8_t, void **info); 511b8adde7SWilliam Kucharski 521b8adde7SWilliam Kucharski /************************************************************************** 531b8adde7SWilliam Kucharski * Utility functions 541b8adde7SWilliam Kucharski **************************************************************************/ 551b8adde7SWilliam Kucharski 561b8adde7SWilliam Kucharski /* Checksum a block. 571b8adde7SWilliam Kucharski */ 581b8adde7SWilliam Kucharski 591b8adde7SWilliam Kucharski uint8_t checksum ( void *block, size_t size ) { 601b8adde7SWilliam Kucharski uint8_t sum = 0; 611b8adde7SWilliam Kucharski uint16_t i = 0; 621b8adde7SWilliam Kucharski for ( i = 0; i < size; i++ ) { 631b8adde7SWilliam Kucharski sum += ( ( uint8_t * ) block )[i]; 641b8adde7SWilliam Kucharski } 651b8adde7SWilliam Kucharski return sum; 661b8adde7SWilliam Kucharski } 671b8adde7SWilliam Kucharski 681b8adde7SWilliam Kucharski /* Print the status of a !PXE structure 691b8adde7SWilliam Kucharski */ 701b8adde7SWilliam Kucharski 711b8adde7SWilliam Kucharski void pxe_dump ( void ) { 721b8adde7SWilliam Kucharski #ifdef TRACE_UNDI 731b8adde7SWilliam Kucharski printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx " 741b8adde7SWilliam Kucharski "BD %hx:%hx BC %hx:%hx\n", 751b8adde7SWilliam Kucharski undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset, 761b8adde7SWilliam Kucharski undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size, 771b8adde7SWilliam Kucharski undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size, 781b8adde7SWilliam Kucharski undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size, 791b8adde7SWilliam Kucharski undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size, 801b8adde7SWilliam Kucharski undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size ); 811b8adde7SWilliam Kucharski #endif 821b8adde7SWilliam Kucharski } 831b8adde7SWilliam Kucharski 841b8adde7SWilliam Kucharski /* Allocate/free space for structures that must reside in base memory 851b8adde7SWilliam Kucharski */ 861b8adde7SWilliam Kucharski 871b8adde7SWilliam Kucharski int allocate_base_mem_data ( void ) { 881b8adde7SWilliam Kucharski /* In GRUB, anything is in base address, so we do not need 891b8adde7SWilliam Kucharski * allocate anything */ 901b8adde7SWilliam Kucharski undi.base_mem_data = &undi_base_mem_data; 911b8adde7SWilliam Kucharski memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 921b8adde7SWilliam Kucharski undi.undi_call_info = &undi.base_mem_data->undi_call_info; 931b8adde7SWilliam Kucharski undi.pxs = &undi.base_mem_data->pxs; 941b8adde7SWilliam Kucharski undi.xmit_data = &undi.base_mem_data->xmit_data; 951b8adde7SWilliam Kucharski undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 961b8adde7SWilliam Kucharski #if 0 /* Etherboot Code */ 971b8adde7SWilliam Kucharski /* Allocate space in base memory. 981b8adde7SWilliam Kucharski * Initialise pointers to base memory structures. 991b8adde7SWilliam Kucharski */ 1001b8adde7SWilliam Kucharski if ( undi.base_mem_data == NULL ) { 1011b8adde7SWilliam Kucharski undi.base_mem_data = 1021b8adde7SWilliam Kucharski allot_base_memory ( sizeof(undi_base_mem_data_t) + 1031b8adde7SWilliam Kucharski TRIVIAL_IRQ_HANDLER_SIZE ); 1041b8adde7SWilliam Kucharski if ( undi.base_mem_data == NULL ) { 1051b8adde7SWilliam Kucharski printf ( "Failed to allocate base memory\n" ); 1061b8adde7SWilliam Kucharski free_base_mem_data(); 1071b8adde7SWilliam Kucharski return 0; 1081b8adde7SWilliam Kucharski } 1091b8adde7SWilliam Kucharski memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 1101b8adde7SWilliam Kucharski undi.undi_call_info = &undi.base_mem_data->undi_call_info; 1111b8adde7SWilliam Kucharski undi.pxs = &undi.base_mem_data->pxs; 1121b8adde7SWilliam Kucharski undi.xmit_data = &undi.base_mem_data->xmit_data; 1131b8adde7SWilliam Kucharski undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 1141b8adde7SWilliam Kucharski copy_trivial_irq_handler ( undi.base_mem_data->irq_handler, 1151b8adde7SWilliam Kucharski TRIVIAL_IRQ_HANDLER_SIZE ); 1161b8adde7SWilliam Kucharski } 1171b8adde7SWilliam Kucharski #endif /* Etherboot Code */ 1181b8adde7SWilliam Kucharski return 1; 1191b8adde7SWilliam Kucharski } 1201b8adde7SWilliam Kucharski 1211b8adde7SWilliam Kucharski int free_base_mem_data ( void ) { 1221b8adde7SWilliam Kucharski /* Just pretend to free something :-) */ 1231b8adde7SWilliam Kucharski undi.base_mem_data = NULL; 1241b8adde7SWilliam Kucharski undi.undi_call_info = NULL; 1251b8adde7SWilliam Kucharski undi.pxs = NULL; 1261b8adde7SWilliam Kucharski undi.xmit_data = NULL; 1271b8adde7SWilliam Kucharski undi.xmit_buffer = NULL; 1281b8adde7SWilliam Kucharski #if 0 /* Etherboot Code */ 1291b8adde7SWilliam Kucharski if ( undi.base_mem_data != NULL ) { 1301b8adde7SWilliam Kucharski forget_base_memory ( undi.base_mem_data, 1311b8adde7SWilliam Kucharski sizeof(undi_base_mem_data_t) + 1321b8adde7SWilliam Kucharski TRIVIAL_IRQ_HANDLER_SIZE ); 1331b8adde7SWilliam Kucharski undi.base_mem_data = NULL; 1341b8adde7SWilliam Kucharski undi.undi_call_info = NULL; 1351b8adde7SWilliam Kucharski undi.pxs = NULL; 1361b8adde7SWilliam Kucharski undi.xmit_data = NULL; 1371b8adde7SWilliam Kucharski undi.xmit_buffer = NULL; 1381b8adde7SWilliam Kucharski copy_trivial_irq_handler ( NULL, 0 ); 1391b8adde7SWilliam Kucharski } 1401b8adde7SWilliam Kucharski #endif /* Etherboot Code */ 1411b8adde7SWilliam Kucharski return 1; 1421b8adde7SWilliam Kucharski } 1431b8adde7SWilliam Kucharski 1441b8adde7SWilliam Kucharski void assemble_firing_squad ( firing_squad_lineup_t *lineup, 1451b8adde7SWilliam Kucharski void *start, size_t size, 1461b8adde7SWilliam Kucharski firing_squad_shoot_t shoot ) { 1471b8adde7SWilliam Kucharski int target; 1481b8adde7SWilliam Kucharski int index; 1491b8adde7SWilliam Kucharski int bit; 1501b8adde7SWilliam Kucharski int start_kb = virt_to_phys(start) >> 10; 1511b8adde7SWilliam Kucharski int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10; 1521b8adde7SWilliam Kucharski 1531b8adde7SWilliam Kucharski for ( target = start_kb; target <= end_kb; target++ ) { 1541b8adde7SWilliam Kucharski index = FIRING_SQUAD_TARGET_INDEX ( target ); 1551b8adde7SWilliam Kucharski bit = FIRING_SQUAD_TARGET_BIT ( target ); 1561b8adde7SWilliam Kucharski lineup->targets[index] = ( shoot << bit ) | 1571b8adde7SWilliam Kucharski ( lineup->targets[index] & ~( 1 << bit ) ); 1581b8adde7SWilliam Kucharski } 1591b8adde7SWilliam Kucharski } 1601b8adde7SWilliam Kucharski 1611b8adde7SWilliam Kucharski void shoot_targets ( firing_squad_lineup_t *lineup ) { 1621b8adde7SWilliam Kucharski int shoot_this_target = 0; 1631b8adde7SWilliam Kucharski int shoot_last_target = 0; 1641b8adde7SWilliam Kucharski int start_target = 0; 1651b8adde7SWilliam Kucharski int target; 1661b8adde7SWilliam Kucharski 1671b8adde7SWilliam Kucharski for ( target = 0; target <= 640; target++ ) { 1681b8adde7SWilliam Kucharski shoot_this_target = ( target == 640 ? 0 : 1691b8adde7SWilliam Kucharski ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) & 1701b8adde7SWilliam Kucharski lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] ); 1711b8adde7SWilliam Kucharski if ( shoot_this_target && !shoot_last_target ) { 1721b8adde7SWilliam Kucharski start_target = target; 1731b8adde7SWilliam Kucharski } else if ( shoot_last_target && !shoot_this_target ) { 1741b8adde7SWilliam Kucharski size_t range_size = ( target - start_target ) << 10; 1751b8adde7SWilliam Kucharski forget_base_memory ( phys_to_virt( start_target<<10 ), 1761b8adde7SWilliam Kucharski range_size ); 1771b8adde7SWilliam Kucharski } 1781b8adde7SWilliam Kucharski shoot_last_target = shoot_this_target; 1791b8adde7SWilliam Kucharski } 1801b8adde7SWilliam Kucharski } 1811b8adde7SWilliam Kucharski 1821b8adde7SWilliam Kucharski /* Debug macros 1831b8adde7SWilliam Kucharski */ 1841b8adde7SWilliam Kucharski 1851b8adde7SWilliam Kucharski #ifdef TRACE_UNDI 1861b8adde7SWilliam Kucharski #define DBG(...) printf ( __VA_ARGS__ ) 1871b8adde7SWilliam Kucharski #else 1881b8adde7SWilliam Kucharski #define DBG(...) 1891b8adde7SWilliam Kucharski #endif 1901b8adde7SWilliam Kucharski 1911b8adde7SWilliam Kucharski #define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \ 1921b8adde7SWilliam Kucharski "SUCCESS" : \ 1931b8adde7SWilliam Kucharski ( (pxs)->Status == PXENV_EXIT_FAILURE ? \ 1941b8adde7SWilliam Kucharski "FAILURE" : "UNKNOWN" ) ) 1951b8adde7SWilliam Kucharski 1961b8adde7SWilliam Kucharski /************************************************************************** 1971b8adde7SWilliam Kucharski * Base memory scanning functions 1981b8adde7SWilliam Kucharski **************************************************************************/ 1991b8adde7SWilliam Kucharski 2001b8adde7SWilliam Kucharski /* Locate the $PnP structure indicating a PnP BIOS. 2011b8adde7SWilliam Kucharski */ 2021b8adde7SWilliam Kucharski 2031b8adde7SWilliam Kucharski int hunt_pnp_bios ( void ) { 2041b8adde7SWilliam Kucharski uint32_t off = 0x10000; 2051b8adde7SWilliam Kucharski 2061b8adde7SWilliam Kucharski DBG ( "Hunting for PnP BIOS..." ); 2071b8adde7SWilliam Kucharski while ( off > 0 ) { 2081b8adde7SWilliam Kucharski off -= 16; 2091b8adde7SWilliam Kucharski undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off ); 2101b8adde7SWilliam Kucharski if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) { 2111b8adde7SWilliam Kucharski DBG ( "found $PnP at f000:%hx...", off ); 2121b8adde7SWilliam Kucharski if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) { 2131b8adde7SWilliam Kucharski DBG ( "invalid checksum\n..." ); 2141b8adde7SWilliam Kucharski continue; 2151b8adde7SWilliam Kucharski } 2161b8adde7SWilliam Kucharski DBG ( "ok\n" ); 2171b8adde7SWilliam Kucharski return 1; 2181b8adde7SWilliam Kucharski } 2191b8adde7SWilliam Kucharski } 2201b8adde7SWilliam Kucharski DBG ( "none found\n" ); 2211b8adde7SWilliam Kucharski undi.pnp_bios = NULL; 2221b8adde7SWilliam Kucharski return 0; 2231b8adde7SWilliam Kucharski } 2241b8adde7SWilliam Kucharski 2251b8adde7SWilliam Kucharski /* Locate the !PXE structure indicating a loaded UNDI driver. 2261b8adde7SWilliam Kucharski */ 2271b8adde7SWilliam Kucharski 2281b8adde7SWilliam Kucharski int hunt_pixie ( void ) { 2291b8adde7SWilliam Kucharski static uint32_t ptr = 0; 2301b8adde7SWilliam Kucharski pxe_t *pxe = NULL; 2311b8adde7SWilliam Kucharski 2321b8adde7SWilliam Kucharski DBG ( "Hunting for pixies..." ); 2331b8adde7SWilliam Kucharski if ( ptr == 0 ) ptr = 0xa0000; 2341b8adde7SWilliam Kucharski while ( ptr > 0x10000 ) { 2351b8adde7SWilliam Kucharski ptr -= 16; 2361b8adde7SWilliam Kucharski pxe = (pxe_t *) phys_to_virt ( ptr ); 2371b8adde7SWilliam Kucharski if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) { 2381b8adde7SWilliam Kucharski DBG ( "found !PXE at %x...", ptr ); 2391b8adde7SWilliam Kucharski if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 2401b8adde7SWilliam Kucharski DBG ( "invalid checksum\n..." ); 2411b8adde7SWilliam Kucharski continue; 2421b8adde7SWilliam Kucharski } 2431b8adde7SWilliam Kucharski if ( ptr < get_free_base_memory() ) { 2441b8adde7SWilliam Kucharski DBG ( "in free base memory!\n\n" 2451b8adde7SWilliam Kucharski "WARNING: a valid !PXE structure was " 2461b8adde7SWilliam Kucharski "found in an area of memory marked " 2471b8adde7SWilliam Kucharski "as free!\n\n" ); 2481b8adde7SWilliam Kucharski undi.pxe = pxe; 2491b8adde7SWilliam Kucharski pxe_dump(); 2501b8adde7SWilliam Kucharski undi.pxe = NULL; 2511b8adde7SWilliam Kucharski DBG ( "\nIgnoring and continuing, but this " 2521b8adde7SWilliam Kucharski "may cause problems later!\n\n" ); 2531b8adde7SWilliam Kucharski continue; 2541b8adde7SWilliam Kucharski } 2551b8adde7SWilliam Kucharski DBG ( "ok\n" ); 2561b8adde7SWilliam Kucharski undi.pxe = pxe; 2571b8adde7SWilliam Kucharski pxe_dump(); 2581b8adde7SWilliam Kucharski DBG ( "Resetting pixie...\n" ); 2591b8adde7SWilliam Kucharski undi_unload_base_code(); 2601b8adde7SWilliam Kucharski eb_pxenv_stop_undi(); 2611b8adde7SWilliam Kucharski pxe_dump(); 2621b8adde7SWilliam Kucharski return 1; 2631b8adde7SWilliam Kucharski } 2641b8adde7SWilliam Kucharski } 2651b8adde7SWilliam Kucharski DBG ( "none found\n" ); 2661b8adde7SWilliam Kucharski ptr = 0; 2671b8adde7SWilliam Kucharski return 0; 2681b8adde7SWilliam Kucharski } 2691b8adde7SWilliam Kucharski 2701b8adde7SWilliam Kucharski /* Locate PCI PnP ROMs. 2711b8adde7SWilliam Kucharski */ 2721b8adde7SWilliam Kucharski 2731b8adde7SWilliam Kucharski int hunt_rom ( void ) { 2741b8adde7SWilliam Kucharski static uint32_t ptr = 0; 2751b8adde7SWilliam Kucharski 2761b8adde7SWilliam Kucharski DBG ( "Hunting for ROMs..." ); 2771b8adde7SWilliam Kucharski if ( ptr == 0 ) ptr = 0x100000; 2781b8adde7SWilliam Kucharski while ( ptr > 0x0c0000 ) { 2791b8adde7SWilliam Kucharski ptr -= 0x800; 2801b8adde7SWilliam Kucharski undi.rom = ( rom_t * ) phys_to_virt ( ptr ); 2811b8adde7SWilliam Kucharski if ( undi.rom->signature == ROM_SIGNATURE ) { 2821b8adde7SWilliam Kucharski pcir_header_t *pcir_header = NULL; 2831b8adde7SWilliam Kucharski pnp_header_t *pnp_header = NULL; 2841b8adde7SWilliam Kucharski 2851b8adde7SWilliam Kucharski DBG ( "found 55AA at %x...", ptr ); 2861b8adde7SWilliam Kucharski if ( undi.rom->pcir_off == 0 ) { 2871b8adde7SWilliam Kucharski DBG ( "not a PCI ROM\n..." ); 2881b8adde7SWilliam Kucharski continue; 2891b8adde7SWilliam Kucharski } 2901b8adde7SWilliam Kucharski pcir_header = (pcir_header_t*)( ( void * ) undi.rom + 2911b8adde7SWilliam Kucharski undi.rom->pcir_off ); 2921b8adde7SWilliam Kucharski if ( pcir_header->signature != PCIR_SIGNATURE ) { 2931b8adde7SWilliam Kucharski DBG ( "invalid PCI signature\n..." ); 2941b8adde7SWilliam Kucharski continue; 2951b8adde7SWilliam Kucharski } 2961b8adde7SWilliam Kucharski DBG ( "PCI:%hx:%hx...", pcir_header->vendor_id, 2971b8adde7SWilliam Kucharski pcir_header->device_id ); 2981b8adde7SWilliam Kucharski if ( ( pcir_header->vendor_id != undi.pci.vendor ) || 2991b8adde7SWilliam Kucharski ( pcir_header->device_id != undi.pci.dev_id ) ) { 3001b8adde7SWilliam Kucharski DBG ( "not me (%hx:%hx)\n...", 3011b8adde7SWilliam Kucharski undi.pci.vendor, 3021b8adde7SWilliam Kucharski undi.pci.dev_id ); 3031b8adde7SWilliam Kucharski continue; 3041b8adde7SWilliam Kucharski } 3051b8adde7SWilliam Kucharski if ( undi.rom->pnp_off == 0 ) { 3061b8adde7SWilliam Kucharski DBG ( "not a PnP ROM\n..." ); 3071b8adde7SWilliam Kucharski continue; 3081b8adde7SWilliam Kucharski } 3091b8adde7SWilliam Kucharski pnp_header = (pnp_header_t*)( ( void * ) undi.rom + 3101b8adde7SWilliam Kucharski undi.rom->pnp_off ); 3111b8adde7SWilliam Kucharski if ( pnp_header->signature != PNP_SIGNATURE ) { 3121b8adde7SWilliam Kucharski DBG ( "invalid $PnP signature\n..." ); 3131b8adde7SWilliam Kucharski continue; 3141b8adde7SWilliam Kucharski } 3151b8adde7SWilliam Kucharski if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) { 3161b8adde7SWilliam Kucharski DBG ( "invalid PnP checksum\n..." ); 3171b8adde7SWilliam Kucharski continue; 3181b8adde7SWilliam Kucharski } 3191b8adde7SWilliam Kucharski DBG ( "ok\n"); 3201b8adde7SWilliam Kucharski printf ("ROM %s by %s\n", 3211b8adde7SWilliam Kucharski pnp_header->product_str_off==0 ? "(unknown)" : 3221b8adde7SWilliam Kucharski (void*)undi.rom+pnp_header->product_str_off, 3231b8adde7SWilliam Kucharski pnp_header->manuf_str_off==0 ? "(unknown)" : 3241b8adde7SWilliam Kucharski (void*)undi.rom+pnp_header->manuf_str_off ); 3251b8adde7SWilliam Kucharski return 1; 3261b8adde7SWilliam Kucharski } 3271b8adde7SWilliam Kucharski } 3281b8adde7SWilliam Kucharski DBG ( "none found\n" ); 3291b8adde7SWilliam Kucharski ptr = 0; 3301b8adde7SWilliam Kucharski undi.rom = NULL; 3311b8adde7SWilliam Kucharski return 0; 3321b8adde7SWilliam Kucharski } 3331b8adde7SWilliam Kucharski 3341b8adde7SWilliam Kucharski /* Locate ROMs containing UNDI drivers. 3351b8adde7SWilliam Kucharski */ 3361b8adde7SWilliam Kucharski 3371b8adde7SWilliam Kucharski int hunt_undi_rom ( void ) { 3381b8adde7SWilliam Kucharski while ( hunt_rom() ) { 3391b8adde7SWilliam Kucharski if ( undi.rom->undi_rom_id_off == 0 ) { 3401b8adde7SWilliam Kucharski DBG ( "Not a PXE ROM\n" ); 3411b8adde7SWilliam Kucharski continue; 3421b8adde7SWilliam Kucharski } 3431b8adde7SWilliam Kucharski undi.undi_rom_id = (undi_rom_id_t *) 3441b8adde7SWilliam Kucharski ( (void *)undi.rom + undi.rom->undi_rom_id_off ); 3451b8adde7SWilliam Kucharski if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) { 3461b8adde7SWilliam Kucharski DBG ( "Invalid UNDI signature\n" ); 3471b8adde7SWilliam Kucharski continue; 3481b8adde7SWilliam Kucharski } 3491b8adde7SWilliam Kucharski printf ( "Revision %d.%d.%d", 3501b8adde7SWilliam Kucharski undi.undi_rom_id->undi_rev[2], 3511b8adde7SWilliam Kucharski undi.undi_rom_id->undi_rev[1], 3521b8adde7SWilliam Kucharski undi.undi_rom_id->undi_rev[0] ); 3531b8adde7SWilliam Kucharski return 1; 3541b8adde7SWilliam Kucharski } 3551b8adde7SWilliam Kucharski return 0; 3561b8adde7SWilliam Kucharski } 3571b8adde7SWilliam Kucharski 3581b8adde7SWilliam Kucharski /************************************************************************** 3591b8adde7SWilliam Kucharski * Low-level UNDI API call wrappers 3601b8adde7SWilliam Kucharski **************************************************************************/ 3611b8adde7SWilliam Kucharski 3621b8adde7SWilliam Kucharski /* Make a real-mode UNDI API call to the UNDI routine at 3631b8adde7SWilliam Kucharski * routine_seg:routine_off, passing in three uint16 parameters on the 3641b8adde7SWilliam Kucharski * real-mode stack. 3651b8adde7SWilliam Kucharski * Calls the assembler wrapper routine __undi_call. 3661b8adde7SWilliam Kucharski */ 3671b8adde7SWilliam Kucharski 3681b8adde7SWilliam Kucharski static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg, 3691b8adde7SWilliam Kucharski uint16_t routine_off, uint16_t st0, 3701b8adde7SWilliam Kucharski uint16_t st1, uint16_t st2 ) { 3711b8adde7SWilliam Kucharski PXENV_EXIT_t ret = PXENV_EXIT_FAILURE; 3721b8adde7SWilliam Kucharski 3731b8adde7SWilliam Kucharski undi.undi_call_info->routine.segment = routine_seg; 3741b8adde7SWilliam Kucharski undi.undi_call_info->routine.offset = routine_off; 3751b8adde7SWilliam Kucharski undi.undi_call_info->stack[0] = st0; 3761b8adde7SWilliam Kucharski undi.undi_call_info->stack[1] = st1; 3771b8adde7SWilliam Kucharski undi.undi_call_info->stack[2] = st2; 3781b8adde7SWilliam Kucharski ret = __undi_call ( SEGMENT( undi.undi_call_info ), 3791b8adde7SWilliam Kucharski OFFSET( undi.undi_call_info ) ); 3801b8adde7SWilliam Kucharski 3811b8adde7SWilliam Kucharski /* UNDI API calls may rudely change the status of A20 and not 3821b8adde7SWilliam Kucharski * bother to restore it afterwards. Intel is known to be 3831b8adde7SWilliam Kucharski * guilty of this. 3841b8adde7SWilliam Kucharski * 3851b8adde7SWilliam Kucharski * Note that we will return to this point even if A20 gets 3861b8adde7SWilliam Kucharski * screwed up by the UNDI driver, because Etherboot always 3871b8adde7SWilliam Kucharski * resides in an even megabyte of RAM. 3881b8adde7SWilliam Kucharski */ 3891b8adde7SWilliam Kucharski gateA20_set(); 3901b8adde7SWilliam Kucharski 3911b8adde7SWilliam Kucharski return ret; 3921b8adde7SWilliam Kucharski } 3931b8adde7SWilliam Kucharski 3941b8adde7SWilliam Kucharski /* Make a real-mode call to the UNDI loader routine at 3951b8adde7SWilliam Kucharski * routine_seg:routine_off, passing in the seg:off address of a 3961b8adde7SWilliam Kucharski * pxenv_structure on the real-mode stack. 3971b8adde7SWilliam Kucharski */ 3981b8adde7SWilliam Kucharski 3991b8adde7SWilliam Kucharski int undi_call_loader ( void ) { 4001b8adde7SWilliam Kucharski PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 4011b8adde7SWilliam Kucharski 4021b8adde7SWilliam Kucharski pxenv_exit = _undi_call ( SEGMENT( undi.rom ), 4031b8adde7SWilliam Kucharski undi.undi_rom_id->undi_loader_off, 4041b8adde7SWilliam Kucharski OFFSET( undi.pxs ), 4051b8adde7SWilliam Kucharski SEGMENT( undi.pxs ), 4061b8adde7SWilliam Kucharski 0 /* Unused for UNDI loader API */ ); 4071b8adde7SWilliam Kucharski /* Return 1 for success, to be consistent with other routines */ 4081b8adde7SWilliam Kucharski if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1; 4091b8adde7SWilliam Kucharski DBG ( "UNDI loader call failed with status %#hx\n", 4101b8adde7SWilliam Kucharski undi.pxs->Status ); 4111b8adde7SWilliam Kucharski return 0; 4121b8adde7SWilliam Kucharski } 4131b8adde7SWilliam Kucharski 4141b8adde7SWilliam Kucharski /* Make a real-mode UNDI API call, passing in the opcode and the 4151b8adde7SWilliam Kucharski * seg:off address of a pxenv_structure on the real-mode stack. 4161b8adde7SWilliam Kucharski * 4171b8adde7SWilliam Kucharski * Two versions: undi_call() will automatically report any failure 4181b8adde7SWilliam Kucharski * codes, undi_call_silent() will not. 4191b8adde7SWilliam Kucharski */ 4201b8adde7SWilliam Kucharski 4211b8adde7SWilliam Kucharski int undi_call_silent ( uint16_t opcode ) { 4221b8adde7SWilliam Kucharski PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 4231b8adde7SWilliam Kucharski 4241b8adde7SWilliam Kucharski pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment, 4251b8adde7SWilliam Kucharski undi.pxe->EntryPointSP.offset, 4261b8adde7SWilliam Kucharski opcode, 4271b8adde7SWilliam Kucharski OFFSET( undi.pxs ), 4281b8adde7SWilliam Kucharski SEGMENT( undi.pxs ) ); 4291b8adde7SWilliam Kucharski /* Return 1 for success, to be consistent with other routines */ 4301b8adde7SWilliam Kucharski return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0; 4311b8adde7SWilliam Kucharski } 4321b8adde7SWilliam Kucharski 4331b8adde7SWilliam Kucharski int undi_call ( uint16_t opcode ) { 4341b8adde7SWilliam Kucharski if ( undi_call_silent ( opcode ) ) return 1; 4351b8adde7SWilliam Kucharski DBG ( "UNDI API call %#hx failed with status %#hx\n", 4361b8adde7SWilliam Kucharski opcode, undi.pxs->Status ); 4371b8adde7SWilliam Kucharski return 0; 4381b8adde7SWilliam Kucharski } 4391b8adde7SWilliam Kucharski 4401b8adde7SWilliam Kucharski /************************************************************************** 4411b8adde7SWilliam Kucharski * High-level UNDI API call wrappers 4421b8adde7SWilliam Kucharski **************************************************************************/ 4431b8adde7SWilliam Kucharski 4441b8adde7SWilliam Kucharski /* Install the UNDI driver from a located UNDI ROM. 4451b8adde7SWilliam Kucharski */ 4461b8adde7SWilliam Kucharski 4471b8adde7SWilliam Kucharski int undi_loader ( void ) { 4481b8adde7SWilliam Kucharski pxe_t *pxe = NULL; 4491b8adde7SWilliam Kucharski 4501b8adde7SWilliam Kucharski /* AX contains PCI bus:devfn (PCI specification) */ 4511b8adde7SWilliam Kucharski undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 4521b8adde7SWilliam Kucharski /* BX and DX set to 0xffff for non-ISAPnP devices 4531b8adde7SWilliam Kucharski * (BIOS boot specification) 4541b8adde7SWilliam Kucharski */ 4551b8adde7SWilliam Kucharski undi.pxs->loader.bx = 0xffff; 4561b8adde7SWilliam Kucharski undi.pxs->loader.dx = 0xffff; 4571b8adde7SWilliam Kucharski /* ES:DI points to PnP BIOS' $PnP structure 4581b8adde7SWilliam Kucharski * (BIOS boot specification) 4591b8adde7SWilliam Kucharski */ 4601b8adde7SWilliam Kucharski undi.pxs->loader.es = 0xf000; 4611b8adde7SWilliam Kucharski undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 4621b8adde7SWilliam Kucharski 4631b8adde7SWilliam Kucharski /* Allocate space for UNDI driver's code and data segments */ 4641b8adde7SWilliam Kucharski undi.driver_code_size = undi.undi_rom_id->code_size; 4651b8adde7SWilliam Kucharski undi.driver_code = UNDI_HEAP; 4661b8adde7SWilliam Kucharski if ( undi.driver_code == NULL ) { 4671b8adde7SWilliam Kucharski printf ( "Could not allocate %d bytes for UNDI code segment\n", 4681b8adde7SWilliam Kucharski undi.driver_code_size ); 4691b8adde7SWilliam Kucharski return 0; 4701b8adde7SWilliam Kucharski } 4711b8adde7SWilliam Kucharski undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code ); 4721b8adde7SWilliam Kucharski 4731b8adde7SWilliam Kucharski undi.driver_data_size = undi.undi_rom_id->data_size; 4741b8adde7SWilliam Kucharski undi.driver_data = (void *)((((unsigned long)UNDI_HEAP + undi.undi_rom_id->code_size) | (1024 -1)) + 1); 4751b8adde7SWilliam Kucharski if ( undi.driver_data == NULL ) { 4761b8adde7SWilliam Kucharski printf ( "Could not allocate %d bytes for UNDI code segment\n", 4771b8adde7SWilliam Kucharski undi.driver_data_size ); 4781b8adde7SWilliam Kucharski return 0; 4791b8adde7SWilliam Kucharski } 4801b8adde7SWilliam Kucharski undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data ); 4811b8adde7SWilliam Kucharski 4821b8adde7SWilliam Kucharski DBG ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n", 4831b8adde7SWilliam Kucharski undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds ); 4841b8adde7SWilliam Kucharski 4851b8adde7SWilliam Kucharski /* Do the API call to install the loader */ 4861b8adde7SWilliam Kucharski if ( ! undi_call_loader () ) return 0; 4871b8adde7SWilliam Kucharski 4881b8adde7SWilliam Kucharski pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 4891b8adde7SWilliam Kucharski DBG ( "UNDI driver created a pixie at %hx:%hx...", 4901b8adde7SWilliam Kucharski undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 4911b8adde7SWilliam Kucharski if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) { 4921b8adde7SWilliam Kucharski DBG ( "invalid signature\n" ); 4931b8adde7SWilliam Kucharski return 0; 4941b8adde7SWilliam Kucharski } 4951b8adde7SWilliam Kucharski if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 4961b8adde7SWilliam Kucharski DBG ( "invalid checksum\n" ); 4971b8adde7SWilliam Kucharski return 0; 4981b8adde7SWilliam Kucharski } 4991b8adde7SWilliam Kucharski DBG ( "ok\n" ); 5001b8adde7SWilliam Kucharski undi.pxe = pxe; 5011b8adde7SWilliam Kucharski pxe_dump(); 5021b8adde7SWilliam Kucharski return 1; 5031b8adde7SWilliam Kucharski } 5041b8adde7SWilliam Kucharski 5051b8adde7SWilliam Kucharski /* Start the UNDI driver. 5061b8adde7SWilliam Kucharski */ 5071b8adde7SWilliam Kucharski 5081b8adde7SWilliam Kucharski int eb_pxenv_start_undi ( void ) { 5091b8adde7SWilliam Kucharski int success = 0; 5101b8adde7SWilliam Kucharski 5111b8adde7SWilliam Kucharski /* AX contains PCI bus:devfn (PCI specification) */ 5121b8adde7SWilliam Kucharski undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 5131b8adde7SWilliam Kucharski /* BX and DX set to 0xffff for non-ISAPnP devices 5141b8adde7SWilliam Kucharski * (BIOS boot specification) 5151b8adde7SWilliam Kucharski */ 5161b8adde7SWilliam Kucharski undi.pxs->start_undi.bx = 0xffff; 5171b8adde7SWilliam Kucharski undi.pxs->start_undi.dx = 0xffff; 5181b8adde7SWilliam Kucharski /* ES:DI points to PnP BIOS' $PnP structure 5191b8adde7SWilliam Kucharski * (BIOS boot specification) 5201b8adde7SWilliam Kucharski */ 5211b8adde7SWilliam Kucharski undi.pxs->start_undi.es = 0xf000; 5221b8adde7SWilliam Kucharski undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 5231b8adde7SWilliam Kucharski 5241b8adde7SWilliam Kucharski DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n", 5251b8adde7SWilliam Kucharski undi.pxs->start_undi.ax, 5261b8adde7SWilliam Kucharski undi.pxs->start_undi.bx, undi.pxs->start_undi.dx, 5271b8adde7SWilliam Kucharski undi.pxs->start_undi.es, undi.pxs->start_undi.di ); 5281b8adde7SWilliam Kucharski success = undi_call ( PXENV_START_UNDI ); 5291b8adde7SWilliam Kucharski DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5301b8adde7SWilliam Kucharski if ( success ) undi.prestarted = 1; 5311b8adde7SWilliam Kucharski return success; 5321b8adde7SWilliam Kucharski } 5331b8adde7SWilliam Kucharski 5341b8adde7SWilliam Kucharski int eb_pxenv_undi_startup ( void ) { 5351b8adde7SWilliam Kucharski int success = 0; 5361b8adde7SWilliam Kucharski 5371b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_STARTUP => (void)\n" ); 5381b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_STARTUP ); 5391b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5401b8adde7SWilliam Kucharski if ( success ) undi.started = 1; 5411b8adde7SWilliam Kucharski return success; 5421b8adde7SWilliam Kucharski } 5431b8adde7SWilliam Kucharski 5441b8adde7SWilliam Kucharski int eb_pxenv_undi_cleanup ( void ) { 5451b8adde7SWilliam Kucharski int success = 0; 5461b8adde7SWilliam Kucharski 5471b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_CLEANUP => (void)\n" ); 5481b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_CLEANUP ); 5491b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5501b8adde7SWilliam Kucharski return success; 5511b8adde7SWilliam Kucharski } 5521b8adde7SWilliam Kucharski 5531b8adde7SWilliam Kucharski int eb_pxenv_undi_initialize ( void ) { 5541b8adde7SWilliam Kucharski int success = 0; 5551b8adde7SWilliam Kucharski 5561b8adde7SWilliam Kucharski undi.pxs->undi_initialize.ProtocolIni = 0; 5571b8adde7SWilliam Kucharski memset ( &undi.pxs->undi_initialize.reserved, 0, 5581b8adde7SWilliam Kucharski sizeof ( undi.pxs->undi_initialize.reserved ) ); 5591b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" ); 5601b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_INITIALIZE ); 5611b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5621b8adde7SWilliam Kucharski if ( success ) undi.initialized = 1; 5631b8adde7SWilliam Kucharski return success; 5641b8adde7SWilliam Kucharski } 5651b8adde7SWilliam Kucharski 5661b8adde7SWilliam Kucharski int eb_pxenv_undi_shutdown ( void ) { 5671b8adde7SWilliam Kucharski int success = 0; 5681b8adde7SWilliam Kucharski 5691b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" ); 5701b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_SHUTDOWN ); 5711b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5721b8adde7SWilliam Kucharski if ( success ) { 5731b8adde7SWilliam Kucharski undi.initialized = 0; 5741b8adde7SWilliam Kucharski undi.started = 0; 5751b8adde7SWilliam Kucharski } 5761b8adde7SWilliam Kucharski return success; 5771b8adde7SWilliam Kucharski } 5781b8adde7SWilliam Kucharski 5791b8adde7SWilliam Kucharski int eb_pxenv_undi_open ( void ) { 5801b8adde7SWilliam Kucharski int success = 0; 5811b8adde7SWilliam Kucharski 5821b8adde7SWilliam Kucharski undi.pxs->undi_open.OpenFlag = 0; 5831b8adde7SWilliam Kucharski undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST; 5841b8adde7SWilliam Kucharski 5851b8adde7SWilliam Kucharski /* Multicast support not yet implemented */ 5861b8adde7SWilliam Kucharski undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0; 5871b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx " 5881b8adde7SWilliam Kucharski "MCastAddrCount=%hx\n", 5891b8adde7SWilliam Kucharski undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter, 5901b8adde7SWilliam Kucharski undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount ); 5911b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_OPEN ); 5921b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 5931b8adde7SWilliam Kucharski if ( success ) undi.opened = 1; 5941b8adde7SWilliam Kucharski return success; 5951b8adde7SWilliam Kucharski } 5961b8adde7SWilliam Kucharski 5971b8adde7SWilliam Kucharski int eb_pxenv_undi_close ( void ) { 5981b8adde7SWilliam Kucharski int success = 0; 5991b8adde7SWilliam Kucharski 6001b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_CLOSE => (void)\n" ); 6011b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_CLOSE ); 6021b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 6031b8adde7SWilliam Kucharski if ( success ) undi.opened = 0; 6041b8adde7SWilliam Kucharski return success; 6051b8adde7SWilliam Kucharski } 6061b8adde7SWilliam Kucharski 6071b8adde7SWilliam Kucharski int eb_pxenv_undi_transmit_packet ( void ) { 6081b8adde7SWilliam Kucharski int success = 0; 6091b8adde7SWilliam Kucharski static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; 6101b8adde7SWilliam Kucharski 6111b8adde7SWilliam Kucharski /* XMitFlag selects unicast / broadcast */ 6121b8adde7SWilliam Kucharski if ( memcmp ( undi.xmit_data->destaddr, broadcast, 6131b8adde7SWilliam Kucharski sizeof(broadcast) ) == 0 ) { 6141b8adde7SWilliam Kucharski undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST; 6151b8adde7SWilliam Kucharski } else { 6161b8adde7SWilliam Kucharski undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR; 6171b8adde7SWilliam Kucharski } 6181b8adde7SWilliam Kucharski 6191b8adde7SWilliam Kucharski /* Zero reserved dwords */ 6201b8adde7SWilliam Kucharski undi.pxs->undi_transmit.Reserved[0] = 0; 6211b8adde7SWilliam Kucharski undi.pxs->undi_transmit.Reserved[1] = 0; 6221b8adde7SWilliam Kucharski 6231b8adde7SWilliam Kucharski /* Segment:offset pointer to DestAddr in base memory */ 6241b8adde7SWilliam Kucharski undi.pxs->undi_transmit.DestAddr.segment = 6251b8adde7SWilliam Kucharski SEGMENT( undi.xmit_data->destaddr ); 6261b8adde7SWilliam Kucharski undi.pxs->undi_transmit.DestAddr.offset = 6271b8adde7SWilliam Kucharski OFFSET( undi.xmit_data->destaddr ); 6281b8adde7SWilliam Kucharski 6291b8adde7SWilliam Kucharski /* Segment:offset pointer to TBD in base memory */ 6301b8adde7SWilliam Kucharski undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd ); 6311b8adde7SWilliam Kucharski undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd ); 6321b8adde7SWilliam Kucharski 6331b8adde7SWilliam Kucharski /* Use only the "immediate" part of the TBD */ 6341b8adde7SWilliam Kucharski undi.xmit_data->tbd.DataBlkCount = 0; 6351b8adde7SWilliam Kucharski 6361b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n" 6371b8adde7SWilliam Kucharski "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n", 6381b8adde7SWilliam Kucharski undi.pxs->undi_transmit.Protocol, 6391b8adde7SWilliam Kucharski undi.pxs->undi_transmit.XmitFlag, 6401b8adde7SWilliam Kucharski undi.pxs->undi_transmit.DestAddr.segment, 6411b8adde7SWilliam Kucharski undi.pxs->undi_transmit.DestAddr.offset, 6421b8adde7SWilliam Kucharski undi.pxs->undi_transmit.TBD.segment, 6431b8adde7SWilliam Kucharski undi.pxs->undi_transmit.TBD.offset ); 6441b8adde7SWilliam Kucharski DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n", 6451b8adde7SWilliam Kucharski undi.xmit_data->tbd.ImmedLength, 6461b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.segment, 6471b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.offset, 6481b8adde7SWilliam Kucharski undi.xmit_data->tbd.DataBlkCount ); 6491b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_TRANSMIT ); 6501b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n", 6511b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs) ); 6521b8adde7SWilliam Kucharski return success; 6531b8adde7SWilliam Kucharski } 6541b8adde7SWilliam Kucharski 6551b8adde7SWilliam Kucharski int eb_pxenv_undi_set_station_address ( void ) { 6561b8adde7SWilliam Kucharski /* This will spuriously fail on some cards. Ignore failures. 6571b8adde7SWilliam Kucharski * We only ever use it to set the MAC address to the card's 6581b8adde7SWilliam Kucharski * permanent value anyway, so it's a useless call (although we 6591b8adde7SWilliam Kucharski * make it because PXE spec says we should). 6601b8adde7SWilliam Kucharski */ 6611b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => " 6621b8adde7SWilliam Kucharski "StationAddress=%!\n", 6631b8adde7SWilliam Kucharski undi.pxs->undi_set_station_address.StationAddress ); 6641b8adde7SWilliam Kucharski undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS ); 6651b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n", 6661b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs) ); 6671b8adde7SWilliam Kucharski return 1; 6681b8adde7SWilliam Kucharski } 6691b8adde7SWilliam Kucharski 6701b8adde7SWilliam Kucharski int eb_pxenv_undi_get_information ( void ) { 6711b8adde7SWilliam Kucharski int success = 0; 6721b8adde7SWilliam Kucharski memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 6731b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" ); 6741b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_GET_INFORMATION ); 6751b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s " 6761b8adde7SWilliam Kucharski "BaseIO=%hx IntNumber=%hx ...\n" 6771b8adde7SWilliam Kucharski "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n" 6781b8adde7SWilliam Kucharski "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n" 6791b8adde7SWilliam Kucharski "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n", 6801b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs), 6811b8adde7SWilliam Kucharski undi.pxs->undi_get_information.BaseIo, 6821b8adde7SWilliam Kucharski undi.pxs->undi_get_information.IntNumber, 6831b8adde7SWilliam Kucharski undi.pxs->undi_get_information.MaxTranUnit, 6841b8adde7SWilliam Kucharski undi.pxs->undi_get_information.HwType, 6851b8adde7SWilliam Kucharski undi.pxs->undi_get_information.HwAddrLen, 6861b8adde7SWilliam Kucharski undi.pxs->undi_get_information.CurrentNodeAddress, 6871b8adde7SWilliam Kucharski undi.pxs->undi_get_information.PermNodeAddress, 6881b8adde7SWilliam Kucharski undi.pxs->undi_get_information.ROMAddress, 6891b8adde7SWilliam Kucharski undi.pxs->undi_get_information.RxBufCt, 6901b8adde7SWilliam Kucharski undi.pxs->undi_get_information.TxBufCt ); 6911b8adde7SWilliam Kucharski return success; 6921b8adde7SWilliam Kucharski } 6931b8adde7SWilliam Kucharski 6941b8adde7SWilliam Kucharski int eb_pxenv_undi_get_iface_info ( void ) { 6951b8adde7SWilliam Kucharski int success = 0; 6961b8adde7SWilliam Kucharski 6971b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" ); 6981b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_GET_IFACE_INFO ); 6991b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n" 7001b8adde7SWilliam Kucharski "... LinkSpeed=%x ServiceFlags=%x\n", 7011b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs), 7021b8adde7SWilliam Kucharski undi.pxs->undi_get_iface_info.IfaceType, 7031b8adde7SWilliam Kucharski undi.pxs->undi_get_iface_info.LinkSpeed, 7041b8adde7SWilliam Kucharski undi.pxs->undi_get_iface_info.ServiceFlags ); 7051b8adde7SWilliam Kucharski return success; 7061b8adde7SWilliam Kucharski } 7071b8adde7SWilliam Kucharski 7081b8adde7SWilliam Kucharski int eb_pxenv_undi_isr ( void ) { 7091b8adde7SWilliam Kucharski int success = 0; 7101b8adde7SWilliam Kucharski 7111b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n", 7121b8adde7SWilliam Kucharski undi.pxs->undi_isr.FuncFlag ); 7131b8adde7SWilliam Kucharski success = undi_call ( PXENV_UNDI_ISR ); 7141b8adde7SWilliam Kucharski DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n" 7151b8adde7SWilliam Kucharski "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx " 7161b8adde7SWilliam Kucharski "ProtType=%hhx ...\n... PktType=%hhx\n", 7171b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag, 7181b8adde7SWilliam Kucharski undi.pxs->undi_isr.BufferLength, 7191b8adde7SWilliam Kucharski undi.pxs->undi_isr.FrameLength, 7201b8adde7SWilliam Kucharski undi.pxs->undi_isr.FrameHeaderLength, 7211b8adde7SWilliam Kucharski undi.pxs->undi_isr.Frame.segment, 7221b8adde7SWilliam Kucharski undi.pxs->undi_isr.Frame.offset, 7231b8adde7SWilliam Kucharski undi.pxs->undi_isr.ProtType, 7241b8adde7SWilliam Kucharski undi.pxs->undi_isr.PktType ); 7251b8adde7SWilliam Kucharski return success; 7261b8adde7SWilliam Kucharski } 7271b8adde7SWilliam Kucharski 7281b8adde7SWilliam Kucharski int eb_pxenv_stop_undi ( void ) { 7291b8adde7SWilliam Kucharski int success = 0; 7301b8adde7SWilliam Kucharski 7311b8adde7SWilliam Kucharski DBG ( "PXENV_STOP_UNDI => (void)\n" ); 7321b8adde7SWilliam Kucharski success = undi_call ( PXENV_STOP_UNDI ); 7331b8adde7SWilliam Kucharski DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 7341b8adde7SWilliam Kucharski if ( success ) undi.prestarted = 0; 7351b8adde7SWilliam Kucharski return success; 7361b8adde7SWilliam Kucharski } 7371b8adde7SWilliam Kucharski 7381b8adde7SWilliam Kucharski int eb_pxenv_unload_stack ( void ) { 7391b8adde7SWilliam Kucharski int success = 0; 7401b8adde7SWilliam Kucharski 7411b8adde7SWilliam Kucharski memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 7421b8adde7SWilliam Kucharski DBG ( "PXENV_UNLOAD_STACK => (void)\n" ); 7431b8adde7SWilliam Kucharski success = undi_call_silent ( PXENV_UNLOAD_STACK ); 7441b8adde7SWilliam Kucharski DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n", 7451b8adde7SWilliam Kucharski UNDI_STATUS(undi.pxs), 7461b8adde7SWilliam Kucharski ( undi.pxs->Status == PXENV_STATUS_SUCCESS ? 7471b8adde7SWilliam Kucharski "base-code is ready to be removed" : 7481b8adde7SWilliam Kucharski ( undi.pxs->Status == PXENV_STATUS_FAILURE ? 7491b8adde7SWilliam Kucharski "the size of free base memory has been changed" : 7501b8adde7SWilliam Kucharski ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ? 7511b8adde7SWilliam Kucharski "the NIC interrupt vector has been changed" : 7521b8adde7SWilliam Kucharski "UNEXPECTED STATUS CODE" ) ) ) ); 7531b8adde7SWilliam Kucharski return success; 7541b8adde7SWilliam Kucharski } 7551b8adde7SWilliam Kucharski 7561b8adde7SWilliam Kucharski int eb_pxenv_stop_base ( void ) { 7571b8adde7SWilliam Kucharski int success = 0; 7581b8adde7SWilliam Kucharski 7591b8adde7SWilliam Kucharski DBG ( "PXENV_STOP_BASE => (void)\n" ); 7601b8adde7SWilliam Kucharski success = undi_call ( PXENV_STOP_BASE ); 7611b8adde7SWilliam Kucharski DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 7621b8adde7SWilliam Kucharski return success; 7631b8adde7SWilliam Kucharski } 7641b8adde7SWilliam Kucharski 7651b8adde7SWilliam Kucharski /* Unload UNDI base code (if any present) and free memory. 7661b8adde7SWilliam Kucharski */ 7671b8adde7SWilliam Kucharski int undi_unload_base_code ( void ) { 7681b8adde7SWilliam Kucharski /* In GRUB, we do not allocate anything, but we still can call 7691b8adde7SWilliam Kucharski * to free the base space */ 7701b8adde7SWilliam Kucharski void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 ); 7711b8adde7SWilliam Kucharski size_t bc_code_size = undi.pxe->BC_Code.Seg_Size; 7721b8adde7SWilliam Kucharski void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 ); 7731b8adde7SWilliam Kucharski size_t bc_data_size = undi.pxe->BC_Data.Seg_Size; 7741b8adde7SWilliam Kucharski void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 ); 7751b8adde7SWilliam Kucharski size_t bc_stck_size = undi.pxe->Stack.Seg_Size; 7761b8adde7SWilliam Kucharski firing_squad_lineup_t lineup; 7771b8adde7SWilliam Kucharski 7781b8adde7SWilliam Kucharski /* Don't unload if there is no base code present */ 7791b8adde7SWilliam Kucharski if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1; 7801b8adde7SWilliam Kucharski 7811b8adde7SWilliam Kucharski /* Since we never start the base code, the only time we should 7821b8adde7SWilliam Kucharski * reach this is if we were loaded via PXE. There are many 7831b8adde7SWilliam Kucharski * different and conflicting versions of the "correct" way to 7841b8adde7SWilliam Kucharski * unload the PXE base code, several of which appear within 7851b8adde7SWilliam Kucharski * the PXE specification itself. This one seems to work for 7861b8adde7SWilliam Kucharski * our purposes. 7871b8adde7SWilliam Kucharski */ 7881b8adde7SWilliam Kucharski eb_pxenv_stop_base(); 7891b8adde7SWilliam Kucharski //eb_pxenv_unload_stack(); 7901b8adde7SWilliam Kucharski /* if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) && 7911b8adde7SWilliam Kucharski ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) { 7921b8adde7SWilliam Kucharski printf ( "Could not free memory allocated to PXE base code: " 7931b8adde7SWilliam Kucharski "possible memory leak\n" ); 7941b8adde7SWilliam Kucharski return 0; 7951b8adde7SWilliam Kucharski }*/ 7961b8adde7SWilliam Kucharski /* Free data structures. Forget what the PXE specification 7971b8adde7SWilliam Kucharski * says about how to calculate the new size of base memory; 7981b8adde7SWilliam Kucharski * basemem.c takes care of all that for us. Note that we also 7991b8adde7SWilliam Kucharski * have to free the stack (even though PXE spec doesn't say 8001b8adde7SWilliam Kucharski * anything about it) because nothing else is going to do so. 8011b8adde7SWilliam Kucharski * 8021b8adde7SWilliam Kucharski * Structures will almost certainly not be kB-aligned and 8031b8adde7SWilliam Kucharski * there's a reasonable chance that the UNDI code or data 8041b8adde7SWilliam Kucharski * portions will lie in the same kB as the base code. Since 8051b8adde7SWilliam Kucharski * forget_base_memory works only in 1kB increments, this means 8061b8adde7SWilliam Kucharski * we have to do some arcane trickery. 8071b8adde7SWilliam Kucharski */ 8081b8adde7SWilliam Kucharski memset ( &lineup, 0, sizeof(lineup) ); 8091b8adde7SWilliam Kucharski if ( SEGMENT(bc_code) != 0 ) 8101b8adde7SWilliam Kucharski assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT ); 8111b8adde7SWilliam Kucharski if ( SEGMENT(bc_data) != 0 ) 8121b8adde7SWilliam Kucharski assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT ); 8131b8adde7SWilliam Kucharski if ( SEGMENT(bc_stck) != 0 ) 8141b8adde7SWilliam Kucharski assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT ); 8151b8adde7SWilliam Kucharski /* Don't shoot any bits of the UNDI driver code or data */ 8161b8adde7SWilliam Kucharski assemble_firing_squad ( &lineup, 8171b8adde7SWilliam Kucharski VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0), 8181b8adde7SWilliam Kucharski undi.pxe->UNDICode.Seg_Size, DONTSHOOT ); 8191b8adde7SWilliam Kucharski assemble_firing_squad ( &lineup, 8201b8adde7SWilliam Kucharski VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0), 8211b8adde7SWilliam Kucharski undi.pxe->UNDIData.Seg_Size, DONTSHOOT ); 8221b8adde7SWilliam Kucharski //shoot_targets ( &lineup ); 8231b8adde7SWilliam Kucharski //undi.pxe->BC_Code.Seg_Addr = 0; 8241b8adde7SWilliam Kucharski //undi.pxe->BC_Data.Seg_Addr = 0; 8251b8adde7SWilliam Kucharski //undi.pxe->Stack.Seg_Addr = 0; 8261b8adde7SWilliam Kucharski 8271b8adde7SWilliam Kucharski /* Free and reallocate our own base memory data structures, to 8281b8adde7SWilliam Kucharski * allow the freed base-code blocks to be fully released. 8291b8adde7SWilliam Kucharski */ 8301b8adde7SWilliam Kucharski free_base_mem_data(); 8311b8adde7SWilliam Kucharski if ( ! allocate_base_mem_data() ) { 8321b8adde7SWilliam Kucharski printf ( "FATAL: memory unaccountably lost\n" ); 8331b8adde7SWilliam Kucharski while ( 1 ) {}; 8341b8adde7SWilliam Kucharski } 8351b8adde7SWilliam Kucharski 8361b8adde7SWilliam Kucharski return 1; 8371b8adde7SWilliam Kucharski } 8381b8adde7SWilliam Kucharski 8391b8adde7SWilliam Kucharski /* UNDI full initialization 8401b8adde7SWilliam Kucharski * 8411b8adde7SWilliam Kucharski * This calls all the various UNDI initialization routines in sequence. 8421b8adde7SWilliam Kucharski */ 8431b8adde7SWilliam Kucharski 8441b8adde7SWilliam Kucharski int undi_full_startup ( void ) { 8451b8adde7SWilliam Kucharski if ( ! eb_pxenv_start_undi() ) return 0; 8461b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_startup() ) return 0; 8471b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_initialize() ) return 0; 8481b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_get_information() ) return 0; 8491b8adde7SWilliam Kucharski undi.irq = undi.pxs->undi_get_information.IntNumber; 8501b8adde7SWilliam Kucharski if ( ! install_undi_irq_handler ( undi.irq, undi.pxe->EntryPointSP ) ) { 8511b8adde7SWilliam Kucharski undi.irq = IRQ_NONE; 8521b8adde7SWilliam Kucharski return 0; 8531b8adde7SWilliam Kucharski } 8541b8adde7SWilliam Kucharski memmove ( &undi.pxs->undi_set_station_address.StationAddress, 8551b8adde7SWilliam Kucharski &undi.pxs->undi_get_information.PermNodeAddress, 8561b8adde7SWilliam Kucharski sizeof (undi.pxs->undi_set_station_address.StationAddress) ); 8571b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_set_station_address() ) return 0; 8581b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_open() ) return 0; 8591b8adde7SWilliam Kucharski /* install_undi_irq_handler leaves irq disabled */ 8601b8adde7SWilliam Kucharski enable_irq ( undi.irq ); 8611b8adde7SWilliam Kucharski return 1; 8621b8adde7SWilliam Kucharski } 8631b8adde7SWilliam Kucharski 8641b8adde7SWilliam Kucharski /* UNDI full shutdown 8651b8adde7SWilliam Kucharski * 8661b8adde7SWilliam Kucharski * This calls all the various UNDI shutdown routines in sequence and 8671b8adde7SWilliam Kucharski * also frees any memory that it can. 8681b8adde7SWilliam Kucharski */ 8691b8adde7SWilliam Kucharski 8701b8adde7SWilliam Kucharski int undi_full_shutdown ( void ) { 8711b8adde7SWilliam Kucharski if ( undi.pxe != NULL ) { 8721b8adde7SWilliam Kucharski /* In case we didn't allocate the driver's memory in the first 8731b8adde7SWilliam Kucharski * place, try to grab the code and data segments and sizes 8741b8adde7SWilliam Kucharski * from the !PXE structure. 8751b8adde7SWilliam Kucharski */ 8761b8adde7SWilliam Kucharski if ( undi.driver_code == NULL ) { 8771b8adde7SWilliam Kucharski undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 8781b8adde7SWilliam Kucharski 0 ); 8791b8adde7SWilliam Kucharski undi.driver_code_size = undi.pxe->UNDICode.Seg_Size; 8801b8adde7SWilliam Kucharski } 8811b8adde7SWilliam Kucharski if ( undi.driver_data == NULL ) { 8821b8adde7SWilliam Kucharski undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 8831b8adde7SWilliam Kucharski 0 ); 8841b8adde7SWilliam Kucharski undi.driver_data_size = undi.pxe->UNDIData.Seg_Size; 8851b8adde7SWilliam Kucharski } 8861b8adde7SWilliam Kucharski 8871b8adde7SWilliam Kucharski /* Ignore errors and continue in the hope of shutting 8881b8adde7SWilliam Kucharski * down anyway 8891b8adde7SWilliam Kucharski */ 8901b8adde7SWilliam Kucharski if ( undi.opened ) eb_pxenv_undi_close(); 8911b8adde7SWilliam Kucharski if ( undi.started ) { 8921b8adde7SWilliam Kucharski eb_pxenv_undi_cleanup(); 8931b8adde7SWilliam Kucharski /* We may get spurious UNDI API errors at this 8941b8adde7SWilliam Kucharski * point. If startup() succeeded but 8951b8adde7SWilliam Kucharski * initialize() failed then according to the 8961b8adde7SWilliam Kucharski * spec, we should call shutdown(). However, 8971b8adde7SWilliam Kucharski * some NICS will fail with a status code 8981b8adde7SWilliam Kucharski * 0x006a (INVALID_STATE). 8991b8adde7SWilliam Kucharski */ 9001b8adde7SWilliam Kucharski eb_pxenv_undi_shutdown(); 9011b8adde7SWilliam Kucharski } 9021b8adde7SWilliam Kucharski if ( undi.irq != IRQ_NONE ) { 9031b8adde7SWilliam Kucharski remove_undi_irq_handler ( undi.irq ); 9041b8adde7SWilliam Kucharski undi.irq = IRQ_NONE; 9051b8adde7SWilliam Kucharski } 9061b8adde7SWilliam Kucharski undi_unload_base_code(); 9071b8adde7SWilliam Kucharski if ( undi.prestarted ) { 9081b8adde7SWilliam Kucharski eb_pxenv_stop_undi(); 9091b8adde7SWilliam Kucharski /* Success OR Failure indicates that memory 9101b8adde7SWilliam Kucharski * can be freed. Any other status code means 9111b8adde7SWilliam Kucharski * that it can't. 9121b8adde7SWilliam Kucharski */ 9131b8adde7SWilliam Kucharski if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) || 9141b8adde7SWilliam Kucharski ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) { 9151b8adde7SWilliam Kucharski printf ("Could not free memory allocated to " 9161b8adde7SWilliam Kucharski "UNDI driver: possible memory leak\n"); 9171b8adde7SWilliam Kucharski return 0; 9181b8adde7SWilliam Kucharski } 9191b8adde7SWilliam Kucharski } 9201b8adde7SWilliam Kucharski } 9211b8adde7SWilliam Kucharski /* Free memory allocated to UNDI driver */ 9221b8adde7SWilliam Kucharski if ( undi.driver_code != NULL ) { 9231b8adde7SWilliam Kucharski /* Clear contents in order to eliminate !PXE and PXENV 9241b8adde7SWilliam Kucharski * signatures to prevent spurious detection via base 9251b8adde7SWilliam Kucharski * memory scan. 9261b8adde7SWilliam Kucharski */ 9271b8adde7SWilliam Kucharski memset ( undi.driver_code, 0, undi.driver_code_size ); 9281b8adde7SWilliam Kucharski /* forget_base_memory ( undi.driver_code, undi.driver_code_size ); */ 9291b8adde7SWilliam Kucharski undi.driver_code = NULL; 9301b8adde7SWilliam Kucharski undi.driver_code_size = 0; 9311b8adde7SWilliam Kucharski } 9321b8adde7SWilliam Kucharski if ( undi.driver_data != NULL ) { 9331b8adde7SWilliam Kucharski /* forget_base_memory ( undi.driver_data, undi.driver_data_size ); */ 9341b8adde7SWilliam Kucharski undi.driver_data = NULL; 9351b8adde7SWilliam Kucharski undi.driver_data_size = 0; 9361b8adde7SWilliam Kucharski } 9371b8adde7SWilliam Kucharski /* !PXE structure now gone; memory freed */ 9381b8adde7SWilliam Kucharski undi.pxe = NULL; 9391b8adde7SWilliam Kucharski return 1; 9401b8adde7SWilliam Kucharski } 9411b8adde7SWilliam Kucharski 9421b8adde7SWilliam Kucharski /************************************************************************** 9431b8adde7SWilliam Kucharski POLL - Wait for a frame 9441b8adde7SWilliam Kucharski ***************************************************************************/ 9451b8adde7SWilliam Kucharski static int undi_poll(struct nic *nic, int retrieve) 9461b8adde7SWilliam Kucharski { 9471b8adde7SWilliam Kucharski /* Fun, fun, fun. UNDI drivers don't use polling; they use 9481b8adde7SWilliam Kucharski * interrupts. We therefore cheat and pretend that an 9491b8adde7SWilliam Kucharski * interrupt has occurred every time undi_poll() is called. 9501b8adde7SWilliam Kucharski * This isn't too much of a hack; PCI devices share IRQs and 9511b8adde7SWilliam Kucharski * so the first thing that a proper ISR should do is call 9521b8adde7SWilliam Kucharski * PXENV_UNDI_ISR to determine whether or not the UNDI NIC 9531b8adde7SWilliam Kucharski * generated the interrupt; there is no harm done by spurious 9541b8adde7SWilliam Kucharski * calls to PXENV_UNDI_ISR. Similarly, we wouldn't be 9551b8adde7SWilliam Kucharski * handling them any more rapidly than the usual rate of 9561b8adde7SWilliam Kucharski * undi_poll() being called even if we did implement a full 9571b8adde7SWilliam Kucharski * ISR. So it should work. Ha! 9581b8adde7SWilliam Kucharski * 9591b8adde7SWilliam Kucharski * Addendum (21/10/03). Some cards don't play nicely with 9601b8adde7SWilliam Kucharski * this trick, so instead of doing it the easy way we have to 9611b8adde7SWilliam Kucharski * go to all the hassle of installing a genuine interrupt 9621b8adde7SWilliam Kucharski * service routine and dealing with the wonderful 8259 9631b8adde7SWilliam Kucharski * Programmable Interrupt Controller. Joy. 9641b8adde7SWilliam Kucharski * 9651b8adde7SWilliam Kucharski * (02/01/2005). A real UNDI ISR is now implemented in, 9661b8adde7SWilliam Kucharski * following Figure 3-4 in PXE spec 2.0. The interrupt 9671b8adde7SWilliam Kucharski * handler, undi_irq_handler, issues PXENV_UNDI_ISR_IN_START. 9681b8adde7SWilliam Kucharski * If the interrupt is ours, the handler sends EOI and bumps the 9691b8adde7SWilliam Kucharski * undi_irq_trigger_count. This polled routine is equivalent 9701b8adde7SWilliam Kucharski * to the "driver strategy routine". 9711b8adde7SWilliam Kucharski * 9721b8adde7SWilliam Kucharski * Another issue is that upper layer await_*() does not handle 9731b8adde7SWilliam Kucharski * coalesced packets. The UNDI implementation on broadcom chips 9741b8adde7SWilliam Kucharski * appear to combine interrupts. If we loop through GET_NEXT, 9751b8adde7SWilliam Kucharski * we may hand up coalesced packets, resulting in drops, and 9761b8adde7SWilliam Kucharski * severe time delay. As a temperary hack, we return as soon as 9771b8adde7SWilliam Kucharski * we get something, remembering where we were (IN_PROCESS 9781b8adde7SWilliam Kucharski * or GET_NEXT). This assume packets are never broken up. 9791b8adde7SWilliam Kucharski * XXX Need to fix upper layer to handle coalesced data. 9801b8adde7SWilliam Kucharski */ 9811b8adde7SWilliam Kucharski 9821b8adde7SWilliam Kucharski static int undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 9831b8adde7SWilliam Kucharski 9841b8adde7SWilliam Kucharski /* See if a hardware interrupt has occurred since the last poll(). 9851b8adde7SWilliam Kucharski */ 9861b8adde7SWilliam Kucharski switch ( undi_opcode ) { 9871b8adde7SWilliam Kucharski case PXENV_UNDI_ISR_IN_PROCESS: 9881b8adde7SWilliam Kucharski if ( ! undi_irq_triggered ( undi.irq ) ) 9891b8adde7SWilliam Kucharski return 0; 9901b8adde7SWilliam Kucharski default: 9911b8adde7SWilliam Kucharski break; 9921b8adde7SWilliam Kucharski } 9931b8adde7SWilliam Kucharski 9941b8adde7SWilliam Kucharski /* We have an interrupt or there is something left from 9951b8adde7SWilliam Kucharski * last poll. Either way, we need to call UNDI ISR. 9961b8adde7SWilliam Kucharski */ 9971b8adde7SWilliam Kucharski nic->packetlen = 0; 9981b8adde7SWilliam Kucharski undi.pxs->undi_isr.FuncFlag = undi_opcode; 9991b8adde7SWilliam Kucharski /* there is no good way to handle this error */ 10001b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_isr() ) { 10011b8adde7SWilliam Kucharski printf ("undi isr call failed: opcode = %d\n", undi_opcode); 10021b8adde7SWilliam Kucharski return 0; 10031b8adde7SWilliam Kucharski } 10041b8adde7SWilliam Kucharski switch ( undi.pxs->undi_isr.FuncFlag ) { 10051b8adde7SWilliam Kucharski case PXENV_UNDI_ISR_OUT_DONE: 10061b8adde7SWilliam Kucharski /* Set opcode back to IN_PROCESS and wait for next intr */ 10071b8adde7SWilliam Kucharski undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 10081b8adde7SWilliam Kucharski return 0; 10091b8adde7SWilliam Kucharski case PXENV_UNDI_ISR_OUT_TRANSMIT: 10101b8adde7SWilliam Kucharski /* We really don't care about transmission complete 10111b8adde7SWilliam Kucharski * interrupts. Move on to next frame. 10121b8adde7SWilliam Kucharski */ 10131b8adde7SWilliam Kucharski undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 10141b8adde7SWilliam Kucharski return 0; 10151b8adde7SWilliam Kucharski case PXENV_UNDI_ISR_OUT_BUSY: 10161b8adde7SWilliam Kucharski /* This should never happen. 10171b8adde7SWilliam Kucharski */ 10181b8adde7SWilliam Kucharski undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 10191b8adde7SWilliam Kucharski printf ( "UNDI ISR thinks it's being re-entered!\n" 10201b8adde7SWilliam Kucharski "Aborting receive\n" ); 10211b8adde7SWilliam Kucharski return 0; 10221b8adde7SWilliam Kucharski case PXENV_UNDI_ISR_OUT_RECEIVE: 10231b8adde7SWilliam Kucharski /* Copy data to receive buffer and move on to next frame */ 10241b8adde7SWilliam Kucharski undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 10251b8adde7SWilliam Kucharski memcpy ( nic->packet + nic->packetlen, 10261b8adde7SWilliam Kucharski VIRTUAL( undi.pxs->undi_isr.Frame.segment, 10271b8adde7SWilliam Kucharski undi.pxs->undi_isr.Frame.offset ), 10281b8adde7SWilliam Kucharski undi.pxs->undi_isr.BufferLength ); 10291b8adde7SWilliam Kucharski nic->packetlen += undi.pxs->undi_isr.BufferLength; 10301b8adde7SWilliam Kucharski break; 10311b8adde7SWilliam Kucharski default: 10321b8adde7SWilliam Kucharski undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 10331b8adde7SWilliam Kucharski printf ( "UNDI ISR returned bizzare status code %d\n", 10341b8adde7SWilliam Kucharski undi.pxs->undi_isr.FuncFlag ); 10351b8adde7SWilliam Kucharski } 10361b8adde7SWilliam Kucharski 10371b8adde7SWilliam Kucharski return nic->packetlen > 0 ? 1 : 0; 10381b8adde7SWilliam Kucharski } 10391b8adde7SWilliam Kucharski 10401b8adde7SWilliam Kucharski /************************************************************************** 10411b8adde7SWilliam Kucharski TRANSMIT - Transmit a frame 10421b8adde7SWilliam Kucharski ***************************************************************************/ 10431b8adde7SWilliam Kucharski static void undi_transmit( 10441b8adde7SWilliam Kucharski struct nic *nic, 10451b8adde7SWilliam Kucharski const char *d, /* Destination */ 10461b8adde7SWilliam Kucharski unsigned int t, /* Type */ 10471b8adde7SWilliam Kucharski unsigned int s, /* size */ 10481b8adde7SWilliam Kucharski const char *p) /* Packet */ 10491b8adde7SWilliam Kucharski { 10501b8adde7SWilliam Kucharski /* Inhibit compiler warning about unused parameter nic */ 10511b8adde7SWilliam Kucharski if ( nic == NULL ) {}; 10521b8adde7SWilliam Kucharski 10531b8adde7SWilliam Kucharski /* Copy destination to buffer in base memory */ 10541b8adde7SWilliam Kucharski memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) ); 10551b8adde7SWilliam Kucharski 10561b8adde7SWilliam Kucharski /* Translate packet type to UNDI packet type */ 10571b8adde7SWilliam Kucharski switch ( t ) { 10581b8adde7SWilliam Kucharski case IP : undi.pxs->undi_transmit.Protocol = P_IP; break; 10591b8adde7SWilliam Kucharski case ARP: undi.pxs->undi_transmit.Protocol = P_ARP; break; 10601b8adde7SWilliam Kucharski case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break; 10611b8adde7SWilliam Kucharski default: undi.pxs->undi_transmit.Protocol = P_UNKNOWN; break; 10621b8adde7SWilliam Kucharski } 10631b8adde7SWilliam Kucharski 10641b8adde7SWilliam Kucharski /* Store packet length in TBD */ 10651b8adde7SWilliam Kucharski undi.xmit_data->tbd.ImmedLength = s; 10661b8adde7SWilliam Kucharski 10671b8adde7SWilliam Kucharski /* Check to see if data to be transmitted is currently in base 10681b8adde7SWilliam Kucharski * memory. If not, allocate temporary storage in base memory 10691b8adde7SWilliam Kucharski * and copy it there. 10701b8adde7SWilliam Kucharski */ 10711b8adde7SWilliam Kucharski if ( SEGMENT( p ) <= 0xffff ) { 10721b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.segment = SEGMENT( p ); 10731b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.offset = OFFSET( p ); 10741b8adde7SWilliam Kucharski } else { 10751b8adde7SWilliam Kucharski memcpy ( undi.xmit_buffer, p, s ); 10761b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer ); 10771b8adde7SWilliam Kucharski undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer ); 10781b8adde7SWilliam Kucharski } 10791b8adde7SWilliam Kucharski 10801b8adde7SWilliam Kucharski eb_pxenv_undi_transmit_packet(); 10811b8adde7SWilliam Kucharski } 10821b8adde7SWilliam Kucharski 10831b8adde7SWilliam Kucharski /************************************************************************** 10841b8adde7SWilliam Kucharski DISABLE - Turn off ethernet interface 10851b8adde7SWilliam Kucharski ***************************************************************************/ 10861b8adde7SWilliam Kucharski static void undi_disable(struct dev *dev) 10871b8adde7SWilliam Kucharski { 10881b8adde7SWilliam Kucharski /* Inhibit compiler warning about unused parameter dev */ 10891b8adde7SWilliam Kucharski if ( dev == NULL ) {}; 10901b8adde7SWilliam Kucharski undi_full_shutdown(); 10911b8adde7SWilliam Kucharski free_base_mem_data(); 10921b8adde7SWilliam Kucharski } 10931b8adde7SWilliam Kucharski 10941b8adde7SWilliam Kucharski /************************************************************************** 10951b8adde7SWilliam Kucharski PROBE - Look for an adapter, this routine's visible to the outside 10961b8adde7SWilliam Kucharski ***************************************************************************/ 10971b8adde7SWilliam Kucharski 10981b8adde7SWilliam Kucharski /* Locate an UNDI driver by first scanning through base memory for an 10991b8adde7SWilliam Kucharski * installed driver and then by scanning for UNDI ROMs and attempting 11001b8adde7SWilliam Kucharski * to install their drivers. 11011b8adde7SWilliam Kucharski */ 11021b8adde7SWilliam Kucharski 11031b8adde7SWilliam Kucharski int hunt_pixies_and_undi_roms ( void ) { 11041b8adde7SWilliam Kucharski static uint8_t hunt_type = HUNT_FOR_PIXIES; 11051b8adde7SWilliam Kucharski 11061b8adde7SWilliam Kucharski if ( hunt_type == HUNT_FOR_PIXIES ) { 11071b8adde7SWilliam Kucharski if ( hunt_pixie() ) { 11081b8adde7SWilliam Kucharski return 1; 11091b8adde7SWilliam Kucharski } 11101b8adde7SWilliam Kucharski } 11111b8adde7SWilliam Kucharski hunt_type = HUNT_FOR_UNDI_ROMS; 11121b8adde7SWilliam Kucharski while ( hunt_undi_rom() ) { 11131b8adde7SWilliam Kucharski if ( undi_loader() ) { 11141b8adde7SWilliam Kucharski return 1; 11151b8adde7SWilliam Kucharski } 11161b8adde7SWilliam Kucharski undi_full_shutdown(); /* Free any allocated memory */ 11171b8adde7SWilliam Kucharski } 11181b8adde7SWilliam Kucharski hunt_type = HUNT_FOR_PIXIES; 11191b8adde7SWilliam Kucharski return 0; 11201b8adde7SWilliam Kucharski } 11211b8adde7SWilliam Kucharski 11221b8adde7SWilliam Kucharski /* The actual Etherboot probe routine. 11231b8adde7SWilliam Kucharski */ 11241b8adde7SWilliam Kucharski 11251b8adde7SWilliam Kucharski static int undi_probe(struct dev *dev, struct pci_device *pci) 11261b8adde7SWilliam Kucharski { 11271b8adde7SWilliam Kucharski struct nic *nic = (struct nic *)dev; 11281b8adde7SWilliam Kucharski 11291b8adde7SWilliam Kucharski /* Zero out global undi structure */ 11301b8adde7SWilliam Kucharski memset ( &undi, 0, sizeof(undi) ); 11311b8adde7SWilliam Kucharski 11321b8adde7SWilliam Kucharski /* Store PCI parameters; we will need them to initialize the UNDI 11331b8adde7SWilliam Kucharski * driver later. 11341b8adde7SWilliam Kucharski */ 11351b8adde7SWilliam Kucharski memcpy ( &undi.pci, pci, sizeof(undi.pci) ); 11361b8adde7SWilliam Kucharski 11371b8adde7SWilliam Kucharski /* Find the BIOS' $PnP structure */ 11381b8adde7SWilliam Kucharski if ( ! hunt_pnp_bios() ) { 11391b8adde7SWilliam Kucharski printf ( "No PnP BIOS found; aborting\n" ); 11401b8adde7SWilliam Kucharski return 0; 11411b8adde7SWilliam Kucharski } 11421b8adde7SWilliam Kucharski 11431b8adde7SWilliam Kucharski /* Allocate base memory data structures */ 11441b8adde7SWilliam Kucharski if ( ! allocate_base_mem_data() ) return 0; 11451b8adde7SWilliam Kucharski 11461b8adde7SWilliam Kucharski /* Search thoroughly for UNDI drivers */ 11471b8adde7SWilliam Kucharski for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) { 11481b8adde7SWilliam Kucharski /* Try to initialise UNDI driver */ 11491b8adde7SWilliam Kucharski DBG ( "Initializing UNDI driver. Please wait...\n" ); 11501b8adde7SWilliam Kucharski if ( ! undi_full_startup() ) { 11511b8adde7SWilliam Kucharski if ( undi.pxs->Status == 11521b8adde7SWilliam Kucharski PXENV_STATUS_UNDI_MEDIATEST_FAILED ) { 11531b8adde7SWilliam Kucharski DBG ( "Cable not connected (code %#hx)\n", 11541b8adde7SWilliam Kucharski PXENV_STATUS_UNDI_MEDIATEST_FAILED ); 11551b8adde7SWilliam Kucharski } 11561b8adde7SWilliam Kucharski continue; 11571b8adde7SWilliam Kucharski } 11581b8adde7SWilliam Kucharski /* Basic information: MAC, IO addr, IRQ */ 11591b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_get_information() ) continue; 11601b8adde7SWilliam Kucharski DBG ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n", 11611b8adde7SWilliam Kucharski undi.pxs->undi_get_information.BaseIo, 11621b8adde7SWilliam Kucharski undi.pxs->undi_get_information.IntNumber, 11631b8adde7SWilliam Kucharski undi.pxs->undi_get_information.CurrentNodeAddress ); 11641b8adde7SWilliam Kucharski /* Fill out MAC address in nic structure */ 11651b8adde7SWilliam Kucharski memcpy ( nic->node_addr, 11661b8adde7SWilliam Kucharski undi.pxs->undi_get_information.CurrentNodeAddress, 11671b8adde7SWilliam Kucharski ETH_ALEN ); 11681b8adde7SWilliam Kucharski /* More diagnostic information including link speed */ 11691b8adde7SWilliam Kucharski if ( ! eb_pxenv_undi_get_iface_info() ) continue; 11701b8adde7SWilliam Kucharski printf ( " NDIS type %s interface at %d Mbps\n", 11711b8adde7SWilliam Kucharski undi.pxs->undi_get_iface_info.IfaceType, 11721b8adde7SWilliam Kucharski undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 ); 11731b8adde7SWilliam Kucharski DBG ("UNDI Stack at %#hx:%#hx",UNDI_STACK_SEG, UNDI_STACK_OFF); 11741b8adde7SWilliam Kucharski dev->disable = undi_disable; 11751b8adde7SWilliam Kucharski nic->poll = undi_poll; 11761b8adde7SWilliam Kucharski nic->transmit = undi_transmit; 11771b8adde7SWilliam Kucharski return 1; 11781b8adde7SWilliam Kucharski } 11791b8adde7SWilliam Kucharski undi_disable ( dev ); /* To free base memory structures */ 11801b8adde7SWilliam Kucharski return 0; 11811b8adde7SWilliam Kucharski } 11821b8adde7SWilliam Kucharski 11831b8adde7SWilliam Kucharski /* UNDI driver states that it is suitable for any PCI NIC (i.e. any 11841b8adde7SWilliam Kucharski * PCI device of class PCI_CLASS_NETWORK_ETHERNET). If there are any 11851b8adde7SWilliam Kucharski * obscure UNDI NICs that have the incorrect PCI class, add them to 11861b8adde7SWilliam Kucharski * this list. 11871b8adde7SWilliam Kucharski */ 11881b8adde7SWilliam Kucharski static struct pci_id undi_nics[] = { 1189*6148443aSJakub Jermar PCI_ROM(0x10de, 0x0057, "ck804", "nVidia Corporation CK804 Ethernet"), 1190*6148443aSJakub Jermar PCI_ROM(0x10de, 0x0373, "mcp55", "nVidia Corporation MCP55 Ethernet") 11911b8adde7SWilliam Kucharski }; 11921b8adde7SWilliam Kucharski 11931b8adde7SWilliam Kucharski struct pci_driver undi_driver = { 11941b8adde7SWilliam Kucharski .type = NIC_DRIVER, 11951b8adde7SWilliam Kucharski .name = "UNDI", 11961b8adde7SWilliam Kucharski .probe = undi_probe, 11971b8adde7SWilliam Kucharski .ids = undi_nics, 11981b8adde7SWilliam Kucharski .id_count = sizeof(undi_nics)/sizeof(undi_nics[0]), 11991b8adde7SWilliam Kucharski .class = PCI_CLASS_NETWORK_ETHERNET, 12001b8adde7SWilliam Kucharski }; 12011b8adde7SWilliam Kucharski 12021b8adde7SWilliam Kucharski /************************************************ 12031b8adde7SWilliam Kucharski * Code for reusing the BIOS provided pxe stack 12041b8adde7SWilliam Kucharski */ 12051b8adde7SWilliam Kucharski 12061b8adde7SWilliam Kucharski /* Verify !PXE structure saved by pxeloader. */ 12071b8adde7SWilliam Kucharski int undi_bios_pxe(void **dhcpreply) 12081b8adde7SWilliam Kucharski { 12091b8adde7SWilliam Kucharski pxe_t *pxe; 12101b8adde7SWilliam Kucharski uint16_t *ptr = (uint16_t *)0x7C80; 12111b8adde7SWilliam Kucharski 12121b8adde7SWilliam Kucharski pxe = (pxe_t *) VIRTUAL(ptr[0], ptr[1]); 12131b8adde7SWilliam Kucharski if (memcmp(pxe->Signature, "!PXE", 4) != 0) { 12141b8adde7SWilliam Kucharski DBG ("invalid !PXE signature at %x:%x\n", ptr[0], ptr[1]); 12151b8adde7SWilliam Kucharski return 0; 12161b8adde7SWilliam Kucharski } 12171b8adde7SWilliam Kucharski 12181b8adde7SWilliam Kucharski if (checksum(pxe, sizeof(pxe_t)) != 0) { 12191b8adde7SWilliam Kucharski DBG ("invalid checksum\n"); 12201b8adde7SWilliam Kucharski return 0; 12211b8adde7SWilliam Kucharski } 12221b8adde7SWilliam Kucharski 12231b8adde7SWilliam Kucharski /* Zero out global undi structure */ 12241b8adde7SWilliam Kucharski memset (&undi, 0, sizeof(undi)); 12251b8adde7SWilliam Kucharski 12261b8adde7SWilliam Kucharski /* Allocate base memory data structures */ 12271b8adde7SWilliam Kucharski if (! allocate_base_mem_data()) return 0; 12281b8adde7SWilliam Kucharski 12291b8adde7SWilliam Kucharski undi.pxe = pxe; 12301b8adde7SWilliam Kucharski pxe_dump(); 12311b8adde7SWilliam Kucharski 12321b8adde7SWilliam Kucharski if (!eb_pxenv_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, dhcpreply)) { 12331b8adde7SWilliam Kucharski DBG ("failed to get cached DHCP reply\n"); 12341b8adde7SWilliam Kucharski return 0; 12351b8adde7SWilliam Kucharski } 12361b8adde7SWilliam Kucharski return 1; 12371b8adde7SWilliam Kucharski } 12381b8adde7SWilliam Kucharski 12391b8adde7SWilliam Kucharski void undi_pxe_disable(void) 12401b8adde7SWilliam Kucharski { 12411b8adde7SWilliam Kucharski /* full shutdown is problematic for some machines */ 12421b8adde7SWilliam Kucharski (void) eb_pxenv_undi_shutdown(); 12431b8adde7SWilliam Kucharski } 12441b8adde7SWilliam Kucharski 12451b8adde7SWilliam Kucharski /* 12461b8adde7SWilliam Kucharski * Various helper functions for dhcp and tftp 12471b8adde7SWilliam Kucharski */ 12481b8adde7SWilliam Kucharski int eb_pxenv_get_cached_info (uint8_t type, void **info) 12491b8adde7SWilliam Kucharski { 12501b8adde7SWilliam Kucharski int success; 12511b8adde7SWilliam Kucharski 12521b8adde7SWilliam Kucharski memset(undi.pxs, 0, sizeof (undi.pxs)); 12531b8adde7SWilliam Kucharski /* Segment:offset pointer to DestAddr in base memory */ 12541b8adde7SWilliam Kucharski undi.pxs->get_cached_info.PacketType = type; 12551b8adde7SWilliam Kucharski undi.pxs->get_cached_info.BufferSize = 0; 12561b8adde7SWilliam Kucharski undi.pxs->get_cached_info.Buffer.segment = 0; 12571b8adde7SWilliam Kucharski undi.pxs->get_cached_info.Buffer.offset = 0; 12581b8adde7SWilliam Kucharski 12591b8adde7SWilliam Kucharski success = undi_call(PXENV_GET_CACHED_INFO); 12601b8adde7SWilliam Kucharski DBG ("PXENV_GET_CACHED_INFO <= Status=%s\n", UNDI_STATUS(undi.pxs)); 12611b8adde7SWilliam Kucharski 12621b8adde7SWilliam Kucharski *info = (void *)VIRTUAL(undi.pxs->get_cached_info.Buffer.segment, 12631b8adde7SWilliam Kucharski undi.pxs->get_cached_info.Buffer.offset); 12641b8adde7SWilliam Kucharski return success; 12651b8adde7SWilliam Kucharski } 12661b8adde7SWilliam Kucharski 12671b8adde7SWilliam Kucharski /* tftp help routines */ 12681b8adde7SWilliam Kucharski int eb_pxenv_tftp_open(char *file, IP4_t serverip, IP4_t gatewayip, 12691b8adde7SWilliam Kucharski uint16_t *pktlen) 12701b8adde7SWilliam Kucharski { 12711b8adde7SWilliam Kucharski int success; 12721b8adde7SWilliam Kucharski memset(undi.pxs, 0, sizeof (undi.pxs)); 12731b8adde7SWilliam Kucharski undi.pxs->tftp_open.ServerIPAddress = serverip; 12741b8adde7SWilliam Kucharski undi.pxs->tftp_open.GatewayIPAddress = gatewayip; 12751b8adde7SWilliam Kucharski undi.pxs->tftp_open.TFTPPort = htons(TFTP_PORT); 12761b8adde7SWilliam Kucharski undi.pxs->tftp_open.PacketSize = TFTP_MAX_PACKET; 12771b8adde7SWilliam Kucharski (void) sprintf(undi.pxs->tftp_open.FileName, "%s", file); 12781b8adde7SWilliam Kucharski success = undi_call(PXENV_TFTP_OPEN); 12791b8adde7SWilliam Kucharski DBG ("PXENV_TFTP_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs)); 12801b8adde7SWilliam Kucharski *pktlen = undi.pxs->tftp_open.PacketSize; 12811b8adde7SWilliam Kucharski return success; 12821b8adde7SWilliam Kucharski } 12831b8adde7SWilliam Kucharski 12841b8adde7SWilliam Kucharski int eb_pxenv_tftp_read(uint8_t *buf, uint16_t *len) 12851b8adde7SWilliam Kucharski { 12861b8adde7SWilliam Kucharski static int tftp_count = 0; 12871b8adde7SWilliam Kucharski 12881b8adde7SWilliam Kucharski int success; 12891b8adde7SWilliam Kucharski memset(undi.pxs, 0, sizeof (undi.pxs)); 12901b8adde7SWilliam Kucharski undi.pxs->tftp_read.Buffer.segment = SEGMENT(buf); 12911b8adde7SWilliam Kucharski undi.pxs->tftp_read.Buffer.offset = OFFSET(buf); 12921b8adde7SWilliam Kucharski success = undi_call(PXENV_TFTP_READ); 12931b8adde7SWilliam Kucharski DBG ("PXENV_TFTP_READ <= Status=%s\n", UNDI_STATUS(undi.pxs)); 12941b8adde7SWilliam Kucharski *len = undi.pxs->tftp_read.BufferSize; 12951b8adde7SWilliam Kucharski tftp_count++; 12961b8adde7SWilliam Kucharski if ((tftp_count % 1000) == 0) 12971b8adde7SWilliam Kucharski noisy_printf("."); 12981b8adde7SWilliam Kucharski return success; 12991b8adde7SWilliam Kucharski } 13001b8adde7SWilliam Kucharski 13011b8adde7SWilliam Kucharski int eb_pxenv_tftp_close(void) 13021b8adde7SWilliam Kucharski { 13031b8adde7SWilliam Kucharski int success; 13041b8adde7SWilliam Kucharski memset(undi.pxs, 0, sizeof (undi.pxs)); 13051b8adde7SWilliam Kucharski success = undi_call(PXENV_TFTP_CLOSE); 13061b8adde7SWilliam Kucharski DBG ("PXENV_TFTP_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs)); 13071b8adde7SWilliam Kucharski return success; 13081b8adde7SWilliam Kucharski } 13091b8adde7SWilliam Kucharski 13101b8adde7SWilliam Kucharski int eb_pxenv_tftp_get_fsize(char *file, IP4_t serverip, IP4_t gatewayip, 13111b8adde7SWilliam Kucharski uint32_t *fsize) 13121b8adde7SWilliam Kucharski { 13131b8adde7SWilliam Kucharski int success; 13141b8adde7SWilliam Kucharski memset(undi.pxs, 0, sizeof (undi.pxs)); 13151b8adde7SWilliam Kucharski undi.pxs->tftp_open.ServerIPAddress = serverip; 13161b8adde7SWilliam Kucharski undi.pxs->tftp_open.GatewayIPAddress = gatewayip; 13171b8adde7SWilliam Kucharski (void) sprintf(undi.pxs->tftp_open.FileName, "%s", file); 13181b8adde7SWilliam Kucharski success = undi_call(PXENV_TFTP_GET_FSIZE); 13191b8adde7SWilliam Kucharski DBG ("PXENV_TFTP_GET_FSIZE <= Status=%s\n", UNDI_STATUS(undi.pxs)); 13201b8adde7SWilliam Kucharski *fsize = undi.pxs->tftp_get_fsize.FileSize; 13211b8adde7SWilliam Kucharski return success; 13221b8adde7SWilliam Kucharski } 1323