⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 undi.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 3 页
字号:
	 *	 * Structures will almost certainly not be kB-aligned and	 * there's a reasonable chance that the UNDI code or data	 * portions will lie in the same kB as the base code.  Since	 * forget_base_memory works only in 1kB increments, this means	 * we have to do some arcane trickery.	 */	memset ( &lineup, 0, sizeof(lineup) );	if ( SEGMENT(bc_code) != 0 )		assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT );	if ( SEGMENT(bc_data) != 0 )		assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT );	if ( SEGMENT(bc_stck) != 0 )		assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT );	/* Don't shoot any bits of the UNDI driver code or data */	assemble_firing_squad ( &lineup,				VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0),				undi.pxe->UNDICode.Seg_Size, DONTSHOOT );	assemble_firing_squad ( &lineup,				VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0),				undi.pxe->UNDIData.Seg_Size, DONTSHOOT );	shoot_targets ( &lineup );	undi.pxe->BC_Code.Seg_Addr = 0;	undi.pxe->BC_Data.Seg_Addr = 0;	undi.pxe->Stack.Seg_Addr = 0;	/* Free and reallocate our own base memory data structures, to	 * allow the freed base-code blocks to be fully released.	 */	free_base_mem_data();	if ( ! allocate_base_mem_data() ) {		printf ( "FATAL: memory unaccountably lost\n" );		while ( 1 ) {};	}	return 1;}/* UNDI full initialization * * This calls all the various UNDI initialization routines in sequence. */int undi_full_startup ( void ) {	if ( ! eb_pxenv_start_undi() ) return 0;	if ( ! eb_pxenv_undi_startup() ) return 0;	if ( ! eb_pxenv_undi_initialize() ) return 0;	if ( ! eb_pxenv_undi_get_information() ) return 0;	undi.irq = undi.pxs->undi_get_information.IntNumber;	if ( ! install_trivial_irq_handler ( undi.irq ) ) {		undi.irq = IRQ_NONE;		return 0;	}	memmove ( &undi.pxs->undi_set_station_address.StationAddress,		  &undi.pxs->undi_get_information.PermNodeAddress,		  sizeof (undi.pxs->undi_set_station_address.StationAddress) );	if ( ! eb_pxenv_undi_set_station_address() ) return 0;	if ( ! eb_pxenv_undi_open() ) return 0;	return 1;}/* UNDI full shutdown * * This calls all the various UNDI shutdown routines in sequence and * also frees any memory that it can. */int undi_full_shutdown ( void ) {	if ( undi.pxe != NULL ) {		/* In case we didn't allocate the driver's memory in the first		 * place, try to grab the code and data segments and sizes		 * from the !PXE structure.		 */		if ( undi.driver_code == NULL ) {			undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr,						   0 );			undi.driver_code_size = undi.pxe->UNDICode.Seg_Size;		}		if ( undi.driver_data == NULL ) {			undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr,						   0 );			undi.driver_data_size = undi.pxe->UNDIData.Seg_Size;		}				/* Ignore errors and continue in the hope of shutting		 * down anyway		 */		if ( undi.opened ) eb_pxenv_undi_close();		if ( undi.started ) {			eb_pxenv_undi_cleanup();			/* We may get spurious UNDI API errors at this			 * point.  If startup() succeeded but			 * initialize() failed then according to the			 * spec, we should call shutdown().  However,			 * some NICS will fail with a status code			 * 0x006a (INVALID_STATE).			 */			eb_pxenv_undi_shutdown();		}		if ( undi.irq != IRQ_NONE ) {			remove_trivial_irq_handler ( undi.irq );			undi.irq = IRQ_NONE;		}		undi_unload_base_code();		if ( undi.prestarted ) {			eb_pxenv_stop_undi();			/* Success OR Failure indicates that memory			 * can be freed.  Any other status code means			 * that it can't.			 */			if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) ||			    ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) {				printf ("Could not free memory allocated to "					"UNDI driver: possible memory leak\n");				return 0;			}		}	}	/* Free memory allocated to UNDI driver */	if ( undi.driver_code != NULL ) {		/* Clear contents in order to eliminate !PXE and PXENV		 * signatures to prevent spurious detection via base		 * memory scan.		 */		memset ( undi.driver_code, 0, undi.driver_code_size );		forget_base_memory ( undi.driver_code, undi.driver_code_size );		undi.driver_code = NULL;		undi.driver_code_size = 0;	}	if ( undi.driver_data != NULL ) {		forget_base_memory ( undi.driver_data, undi.driver_data_size );		undi.driver_data = NULL;		undi.driver_data_size = 0;	}	/* !PXE structure now gone; memory freed */	undi.pxe = NULL;	return 1;}/**************************************************************************POLL - Wait for a frame***************************************************************************/static int undi_poll(struct nic *nic){	/* Fun, fun, fun.  UNDI drivers don't use polling; they use	 * interrupts.  We therefore cheat and pretend that an	 * interrupt has occurred every time undi_poll() is called.	 * This isn't too much of a hack; PCI devices share IRQs and	 * so the first thing that a proper ISR should do is call	 * PXENV_UNDI_ISR to determine whether or not the UNDI NIC	 * generated the interrupt; there is no harm done by spurious	 * calls to PXENV_UNDI_ISR.  Similarly, we wouldn't be	 * handling them any more rapidly than the usual rate of	 * undi_poll() being called even if we did implement a full	 * ISR.  So it should work.  Ha!	 *	 * Addendum (21/10/03).  Some cards don't play nicely with	 * this trick, so instead of doing it the easy way we have to	 * go to all the hassle of installing a genuine interrupt	 * service routine and dealing with the wonderful 8259	 * Programmable Interrupt Controller.  Joy.	 */	/* See if a hardware interrupt has occurred since the last poll().	 */	if ( ! trivial_irq_triggered ( undi.irq ) ) return 0;	/* Ask the UNDI driver if this is "our" interrupt.	 */	undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;	if ( ! eb_pxenv_undi_isr() ) return 0;	if ( undi.pxs->undi_isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS ) {		/* "Not our interrupt" translates to "no packet ready		 * to read".		 */		return 0;	}	/* At this stage, the device should have cleared its interrupt	 * line so we can send EOI to the 8259.	 */	send_specific_eoi ( undi.irq );	/* We might have received a packet, or this might be a	 * "transmit completed" interrupt.  Zero nic->packetlen,	 * increment whenever we receive a bit of a packet, test	 * nic->packetlen when we're done to see whether or not we	 * actually received anything.	 */	nic->packetlen = 0;	undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;	if ( ! eb_pxenv_undi_isr() ) return 0;	while ( undi.pxs->undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE ) {		switch ( undi.pxs->undi_isr.FuncFlag ) {		case PXENV_UNDI_ISR_OUT_TRANSMIT:			/* We really don't care about transmission complete			 * interrupts.			 */			break;		case PXENV_UNDI_ISR_OUT_BUSY:			/* This should never happen.			 */			printf ( "UNDI ISR thinks it's being re-entered!\n"				 "Aborting receive\n" );			return 0;		case PXENV_UNDI_ISR_OUT_RECEIVE:			/* Copy data to receive buffer */			memcpy ( nic->packet + nic->packetlen,				 VIRTUAL( undi.pxs->undi_isr.Frame.segment,					  undi.pxs->undi_isr.Frame.offset ),				 undi.pxs->undi_isr.BufferLength );			nic->packetlen += undi.pxs->undi_isr.BufferLength;			break;		default:			printf ( "UNDI ISR returned bizzare status code %d\n",				 undi.pxs->undi_isr.FuncFlag );		}		undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;		if ( ! eb_pxenv_undi_isr() ) return 0;	}	return nic->packetlen > 0 ? 1 : 0;}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void undi_transmit(	struct nic *nic,	const char *d,			/* Destination */	unsigned int t,			/* Type */	unsigned int s,			/* size */	const char *p)			/* Packet */{	/* Inhibit compiler warning about unused parameter nic */	if ( nic == NULL ) {};	/* Copy destination to buffer in base memory */	memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) );	/* Translate packet type to UNDI packet type */	switch ( t ) {	case IP :  undi.pxs->undi_transmit.Protocol = P_IP;   break;	case ARP:  undi.pxs->undi_transmit.Protocol = P_ARP;  break;	case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break;	default: printf ( "Unknown packet type %hx\n", t );		return;	}	/* Store packet length in TBD */	undi.xmit_data->tbd.ImmedLength = s;	/* Check to see if data to be transmitted is currently in base	 * memory.  If not, allocate temporary storage in base memory	 * and copy it there.	 */	if ( SEGMENT( p ) <= 0xffff ) {		undi.xmit_data->tbd.Xmit.segment = SEGMENT( p );		undi.xmit_data->tbd.Xmit.offset = OFFSET( p );	} else {		memcpy ( undi.xmit_buffer, p, s );		undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer );		undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer );	}	eb_pxenv_undi_transmit_packet();}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/static void undi_disable(struct dev *dev){	/* Inhibit compiler warning about unused parameter dev */	if ( dev == NULL ) {};	undi_full_shutdown();	free_base_mem_data();}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outside***************************************************************************//* Locate an UNDI driver by first scanning through base memory for an * installed driver and then by scanning for UNDI ROMs and attempting * to install their drivers. */int hunt_pixies_and_undi_roms ( void ) {	static uint8_t hunt_type = HUNT_FOR_PIXIES;		if ( hunt_type == HUNT_FOR_PIXIES ) {		if ( hunt_pixie() ) {			return 1;		}	}	hunt_type = HUNT_FOR_UNDI_ROMS;	while ( hunt_undi_rom() ) {		if ( undi_loader() ) {			return 1;		}		undi_full_shutdown(); /* Free any allocated memory */	}	hunt_type = HUNT_FOR_PIXIES;	return 0;}/* The actual Etherboot probe routine. */static int undi_probe(struct dev *dev, struct pci_device *pci){	struct nic *nic = (struct nic *)dev;	/* Zero out global undi structure */	memset ( &undi, 0, sizeof(undi) );	/* Store PCI parameters; we will need them to initialize the UNDI	 * driver later.	 */	memcpy ( &undi.pci, pci, sizeof(undi.pci) );	/* Find the BIOS' $PnP structure */	if ( ! hunt_pnp_bios() ) {		printf ( "No PnP BIOS found; aborting\n" );		return 0;	}	/* Allocate base memory data structures */	if ( ! allocate_base_mem_data() ) return 0;	/* Search thoroughly for UNDI drivers */	for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) {		/* Try to initialise UNDI driver */		printf ( "Initializing UNDI driver.  Please wait...\n" );		if ( ! undi_full_startup() ) {			if ( undi.pxs->Status ==			     PXENV_STATUS_UNDI_MEDIATEST_FAILED ) {				printf ( "Cable not connected (code %#hx)\n",					 PXENV_STATUS_UNDI_MEDIATEST_FAILED );			}			continue;		}		/* Basic information: MAC, IO addr, IRQ */		if ( ! eb_pxenv_undi_get_information() ) continue;		printf ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n",			 undi.pxs->undi_get_information.BaseIo,			 undi.pxs->undi_get_information.IntNumber,			 undi.pxs->undi_get_information.CurrentNodeAddress );		/* Fill out MAC address in nic structure */		memcpy ( nic->node_addr,			 undi.pxs->undi_get_information.CurrentNodeAddress,			 ETH_ALEN );		/* More diagnostic information including link speed */		if ( ! eb_pxenv_undi_get_iface_info() ) continue;		printf ( "NDIS type %s interface at %d Mbps\n",			 undi.pxs->undi_get_iface_info.IfaceType,			 undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 );		dev->disable  = undi_disable;		nic->poll     = undi_poll;		nic->transmit = undi_transmit;		return 1;	}	undi_disable ( dev ); /* To free base memory structures */	return 0;}/* UNDI driver states that it is suitable for any PCI NIC (i.e. any * PCI device of class PCI_CLASS_NETWORK_ETHERNET).  If there are any * obscure UNDI NICs that have the incorrect PCI class, add them to * this list. */static struct pci_id undi_nics[] = {	/* PCI_ROM(0x0000, 0x0000, "undi", "UNDI adaptor"), */};static struct pci_driver undi_driver __pci_driver = {	.type     = NIC_DRIVER,	.name     = "UNDI",	.probe    = undi_probe,	.ids      = undi_nics, 	.id_count = sizeof(undi_nics)/sizeof(undi_nics[0]),	.class    = PCI_CLASS_NETWORK_ETHERNET,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -