📄 undi.c
字号:
/* Make a real-mode UNDI API call, passing in the opcode and the * seg:off address of a pxenv_structure on the real-mode stack. * * Two versions: undi_call() will automatically report any failure * codes, undi_call_silent() will not. */int undi_call_silent ( uint16_t opcode ) { PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset, opcode, OFFSET( undi.pxs ), SEGMENT( undi.pxs ) ); /* Return 1 for success, to be consistent with other routines */ return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0;}int undi_call ( uint16_t opcode ) { if ( undi_call_silent ( opcode ) ) return 1; printf ( "UNDI API call %#hx failed with status %#hx\n", opcode, undi.pxs->Status ); return 0;}/************************************************************************** * High-level UNDI API call wrappers **************************************************************************//* Install the UNDI driver from a located UNDI ROM. */int undi_loader ( void ) { pxe_t *pxe = NULL; /* AX contains PCI bus:devfn (PCI specification) */ undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; /* BX and DX set to 0xffff for non-ISAPnP devices * (BIOS boot specification) */ undi.pxs->loader.bx = 0xffff; undi.pxs->loader.dx = 0xffff; /* ES:DI points to PnP BIOS' $PnP structure * (BIOS boot specification) */ undi.pxs->loader.es = 0xf000; undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; /* Allocate space for UNDI driver's code and data segments */ undi.driver_code_size = undi.undi_rom_id->code_size; undi.driver_code = allot_base_memory ( undi.driver_code_size ); if ( undi.driver_code == NULL ) { printf ( "Could not allocate %d bytes for UNDI code segment\n", undi.driver_code_size ); return 0; } undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code ); undi.driver_data_size = undi.undi_rom_id->data_size; undi.driver_data = allot_base_memory ( undi.driver_data_size ); if ( undi.driver_data == NULL ) { printf ( "Could not allocate %d bytes for UNDI code segment\n", undi.driver_data_size ); return 0; } undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data ); printf ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n", undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds ); /* Do the API call to install the loader */ if ( ! undi_call_loader () ) return 0; pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); printf ( "UNDI driver created a pixie at %hx:%hx...", undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) { printf ( "invalid signature\n" ); return 0; } if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { printf ( "invalid checksum\n" ); return 0; } printf ( "ok\n" ); undi.pxe = pxe; pxe_dump(); return 1;}/* Start the UNDI driver. */int eb_pxenv_start_undi ( void ) { int success = 0; /* AX contains PCI bus:devfn (PCI specification) */ undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; /* BX and DX set to 0xffff for non-ISAPnP devices * (BIOS boot specification) */ undi.pxs->start_undi.bx = 0xffff; undi.pxs->start_undi.dx = 0xffff; /* ES:DI points to PnP BIOS' $PnP structure * (BIOS boot specification) */ undi.pxs->start_undi.es = 0xf000; undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n", undi.pxs->start_undi.ax, undi.pxs->start_undi.bx, undi.pxs->start_undi.dx, undi.pxs->start_undi.es, undi.pxs->start_undi.di ); success = undi_call ( PXENV_START_UNDI ); DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.prestarted = 1; return success;}int eb_pxenv_undi_startup ( void ) { int success = 0; DBG ( "PXENV_UNDI_STARTUP => (void)\n" ); success = undi_call ( PXENV_UNDI_STARTUP ); DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.started = 1; return success;}int eb_pxenv_undi_cleanup ( void ) { int success = 0; DBG ( "PXENV_UNDI_CLEANUP => (void)\n" ); success = undi_call ( PXENV_UNDI_CLEANUP ); DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); return success;}int eb_pxenv_undi_initialize ( void ) { int success = 0; undi.pxs->undi_initialize.ProtocolIni = 0; memset ( &undi.pxs->undi_initialize.reserved, 0, sizeof ( undi.pxs->undi_initialize.reserved ) ); DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" ); success = undi_call ( PXENV_UNDI_INITIALIZE ); DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.initialized = 1; return success;}int eb_pxenv_undi_shutdown ( void ) { int success = 0; DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" ); success = undi_call ( PXENV_UNDI_SHUTDOWN ); DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) { undi.initialized = 0; undi.started = 0; } return success;}int eb_pxenv_undi_open ( void ) { int success = 0; undi.pxs->undi_open.OpenFlag = 0; undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST; /* Multicast support not yet implemented */ undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0; DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx " "MCastAddrCount=%hx\n", undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter, undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount ); success = undi_call ( PXENV_UNDI_OPEN ); DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.opened = 1; return success; }int eb_pxenv_undi_close ( void ) { int success = 0; DBG ( "PXENV_UNDI_CLOSE => (void)\n" ); success = undi_call ( PXENV_UNDI_CLOSE ); DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.opened = 0; return success;}int eb_pxenv_undi_transmit_packet ( void ) { int success = 0; static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; /* XMitFlag selects unicast / broadcast */ if ( memcmp ( undi.xmit_data->destaddr, broadcast, sizeof(broadcast) ) == 0 ) { undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST; } else { undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR; } /* Zero reserved dwords */ undi.pxs->undi_transmit.Reserved[0] = 0; undi.pxs->undi_transmit.Reserved[1] = 0; /* Segment:offset pointer to DestAddr in base memory */ undi.pxs->undi_transmit.DestAddr.segment = SEGMENT( undi.xmit_data->destaddr ); undi.pxs->undi_transmit.DestAddr.offset = OFFSET( undi.xmit_data->destaddr ); /* Segment:offset pointer to TBD in base memory */ undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd ); undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd ); /* Use only the "immediate" part of the TBD */ undi.xmit_data->tbd.DataBlkCount = 0; DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n" "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n", undi.pxs->undi_transmit.Protocol, undi.pxs->undi_transmit.XmitFlag, undi.pxs->undi_transmit.DestAddr.segment, undi.pxs->undi_transmit.DestAddr.offset, undi.pxs->undi_transmit.TBD.segment, undi.pxs->undi_transmit.TBD.offset ); DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n", undi.xmit_data->tbd.ImmedLength, undi.xmit_data->tbd.Xmit.segment, undi.xmit_data->tbd.Xmit.offset, undi.xmit_data->tbd.DataBlkCount ); success = undi_call ( PXENV_UNDI_TRANSMIT ); DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n", UNDI_STATUS(undi.pxs) ); return success;}int eb_pxenv_undi_set_station_address ( void ) { /* This will spuriously fail on some cards. Ignore failures. * We only ever use it to set the MAC address to the card's * permanent value anyway, so it's a useless call (although we * make it because PXE spec says we should). */ DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => " "StationAddress=%!\n", undi.pxs->undi_set_station_address.StationAddress ); undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS ); DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n", UNDI_STATUS(undi.pxs) ); return 1;}int eb_pxenv_undi_get_information ( void ) { int success = 0; memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" ); success = undi_call ( PXENV_UNDI_GET_INFORMATION ); DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s " "BaseIO=%hx IntNumber=%hx ...\n" "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n" "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n" "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n", UNDI_STATUS(undi.pxs), undi.pxs->undi_get_information.BaseIo, undi.pxs->undi_get_information.IntNumber, undi.pxs->undi_get_information.MaxTranUnit, undi.pxs->undi_get_information.HwType, undi.pxs->undi_get_information.HwAddrLen, undi.pxs->undi_get_information.CurrentNodeAddress, undi.pxs->undi_get_information.PermNodeAddress, undi.pxs->undi_get_information.ROMAddress, undi.pxs->undi_get_information.RxBufCt, undi.pxs->undi_get_information.TxBufCt ); return success;}int eb_pxenv_undi_get_iface_info ( void ) { int success = 0; DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" ); success = undi_call ( PXENV_UNDI_GET_IFACE_INFO ); DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n" "... LinkSpeed=%x ServiceFlags=%x\n", UNDI_STATUS(undi.pxs), undi.pxs->undi_get_iface_info.IfaceType, undi.pxs->undi_get_iface_info.LinkSpeed, undi.pxs->undi_get_iface_info.ServiceFlags ); return success;}int eb_pxenv_undi_isr ( void ) { int success = 0; DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n", undi.pxs->undi_isr.FuncFlag ); success = undi_call ( PXENV_UNDI_ISR ); DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n" "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx " "ProtType=%hhx ...\n... PktType=%hhx\n", UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag, undi.pxs->undi_isr.BufferLength, undi.pxs->undi_isr.FrameLength, undi.pxs->undi_isr.FrameHeaderLength, undi.pxs->undi_isr.Frame.segment, undi.pxs->undi_isr.Frame.offset, undi.pxs->undi_isr.ProtType, undi.pxs->undi_isr.PktType ); return success;}int eb_pxenv_stop_undi ( void ) { int success = 0; DBG ( "PXENV_STOP_UNDI => (void)\n" ); success = undi_call ( PXENV_STOP_UNDI ); DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); if ( success ) undi.prestarted = 0; return success;}int eb_pxenv_unload_stack ( void ) { int success = 0; memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); DBG ( "PXENV_UNLOAD_STACK => (void)\n" ); success = undi_call_silent ( PXENV_UNLOAD_STACK ); DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n", UNDI_STATUS(undi.pxs), ( undi.pxs->Status == PXENV_STATUS_SUCCESS ? "base-code is ready to be removed" : ( undi.pxs->Status == PXENV_STATUS_FAILURE ? "the size of free base memory has been changed" : ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ? "the NIC interrupt vector has been changed" : "UNEXPECTED STATUS CODE" ) ) ) ); return success;}int eb_pxenv_stop_base ( void ) { int success = 0; DBG ( "PXENV_STOP_BASE => (void)\n" ); success = undi_call ( PXENV_STOP_BASE ); DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); return success;}/* Unload UNDI base code (if any present) and free memory. */int undi_unload_base_code ( void ) { void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 ); size_t bc_code_size = undi.pxe->BC_Code.Seg_Size; void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 ); size_t bc_data_size = undi.pxe->BC_Data.Seg_Size; void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 ); size_t bc_stck_size = undi.pxe->Stack.Seg_Size; firing_squad_lineup_t lineup; /* Don't unload if there is no base code present */ if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1; /* Since we never start the base code, the only time we should * reach this is if we were loaded via PXE. There are many * different and conflicting versions of the "correct" way to * unload the PXE base code, several of which appear within * the PXE specification itself. This one seems to work for * our purposes. */ eb_pxenv_stop_base(); eb_pxenv_unload_stack(); if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) && ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) { printf ( "Could not free memory allocated to PXE base code: " "possible memory leak\n" ); return 0; } /* Free data structures. Forget what the PXE specification * says about how to calculate the new size of base memory; * basemem.c takes care of all that for us. Note that we also * have to free the stack (even though PXE spec doesn't say * anything about it) because nothing else is going to do so.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -