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

📄 undi.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 3 页
字号:
/**************************************************************************Etherboot -  BOOTP/TFTP Bootstrap ProgramUNDI NIC driver for EtherbootThis file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>of Fen Systems Ltd. (http://www.fensystems.co.uk/).  All rightsreserved.$Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $***************************************************************************//* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. *//* to get some global routines like printf */#include "etherboot.h"/* to get the interface to the body of the program */#include "nic.h"/* to get the PCI support functions, if this is a PCI NIC */#include "pci.h"/* UNDI and PXE defines.  Includes pxe.h. */#include "undi.h"/* 8259 PIC defines */#include "pic8259.h"/* NIC specific static variables go here */static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL,		       NULL, NULL, 0, NULL, 0, NULL,		       0, 0, 0, 0,		       { 0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL },		       IRQ_NONE };/* Function prototypes */int allocate_base_mem_data ( void );int free_base_mem_data ( void );int eb_pxenv_undi_shutdown ( void );int eb_pxenv_stop_undi ( void );int undi_unload_base_code ( void );int undi_full_shutdown ( void );/************************************************************************** * Utility functions **************************************************************************//* Checksum a block. */uint8_t checksum ( void *block, size_t size ) {	uint8_t sum = 0;	uint16_t i = 0;	for ( i = 0; i < size; i++ ) {		sum += ( ( uint8_t * ) block )[i];	}	return sum;}/* Print the status of a !PXE structure */void pxe_dump ( void ) {	printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx "		 "BD %hx:%hx BC %hx:%hx\n",		 undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset,		 undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size,		 undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size,		 undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size,		 undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size,		 undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size );}/* Allocate/free space for structures that must reside in base memory */int allocate_base_mem_data ( void ) {	/* Allocate space in base memory.	 * Initialise pointers to base memory structures.	 */	if ( undi.base_mem_data == NULL ) {		undi.base_mem_data =			allot_base_memory ( sizeof(undi_base_mem_data_t) +					    TRIVIAL_IRQ_HANDLER_SIZE );		if ( undi.base_mem_data == NULL ) {			printf ( "Failed to allocate base memory\n" );			free_base_mem_data();			return 0;		}		memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );		undi.undi_call_info = &undi.base_mem_data->undi_call_info;		undi.pxs = &undi.base_mem_data->pxs;		undi.xmit_data = &undi.base_mem_data->xmit_data;		undi.xmit_buffer = undi.base_mem_data->xmit_buffer;		copy_trivial_irq_handler ( undi.base_mem_data->irq_handler,					   TRIVIAL_IRQ_HANDLER_SIZE );	}	return 1;}int free_base_mem_data ( void ) {	if ( undi.base_mem_data != NULL ) {		forget_base_memory ( undi.base_mem_data,				     sizeof(undi_base_mem_data_t) +				     TRIVIAL_IRQ_HANDLER_SIZE );		undi.base_mem_data = NULL;		undi.undi_call_info = NULL;		undi.pxs = NULL;		undi.xmit_data = NULL;		undi.xmit_buffer = NULL;		copy_trivial_irq_handler ( NULL, 0 );	}	return 1;}void assemble_firing_squad ( firing_squad_lineup_t *lineup,			     void *start, size_t size,			     firing_squad_shoot_t shoot ) {	int target;	int index;	int bit;	int start_kb = virt_to_phys(start) >> 10;	int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10;		for ( target = start_kb; target <= end_kb; target++ ) {		index = FIRING_SQUAD_TARGET_INDEX ( target );		bit = FIRING_SQUAD_TARGET_BIT ( target );		lineup->targets[index] = ( shoot << bit ) |			( lineup->targets[index] & ~( 1 << bit ) );	}}void shoot_targets ( firing_squad_lineup_t *lineup ) {	int shoot_this_target = 0;	int shoot_last_target = 0;	int start_target = 0;	int target;	for ( target = 0; target <= 640; target++ ) {		shoot_this_target = ( target == 640 ? 0 : 		      ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) &		      lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] );		if ( shoot_this_target && !shoot_last_target ) {			start_target = target;		} else if ( shoot_last_target && !shoot_this_target ) {			size_t range_size = ( target - start_target ) << 10;			forget_base_memory ( phys_to_virt( start_target<<10 ),					     range_size );		}		shoot_last_target = shoot_this_target;	}}/* Debug macros */#ifdef TRACE_UNDI#define DBG(...) printf ( __VA_ARGS__ )#else#define DBG(...)#endif#define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \			      "SUCCESS" : \			      ( (pxs)->Status == PXENV_EXIT_FAILURE ? \				"FAILURE" : "UNKNOWN" ) )/************************************************************************** * Base memory scanning functions **************************************************************************//* Locate the $PnP structure indicating a PnP BIOS. */int hunt_pnp_bios ( void ) {	uint32_t off = 0x10000;	printf ( "Hunting for PnP BIOS..." );	while ( off > 0 ) {		off -= 16;		undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off );		if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) {			printf ( "found $PnP at f000:%hx...", off );			if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) {				printf ( "invalid checksum\n..." );				continue;			}			printf ( "ok\n" );			return 1;		}	}	printf ( "none found\n" );	undi.pnp_bios = NULL;	return 0;}/* Locate the !PXE structure indicating a loaded UNDI driver. */int hunt_pixie ( void ) {	static uint32_t ptr = 0;	pxe_t *pxe = NULL;	printf ( "Hunting for pixies..." );	if ( ptr == 0 ) ptr = 0xa0000;	while ( ptr > 0x10000 ) {		ptr -= 16;		pxe = (pxe_t *) phys_to_virt ( ptr );		if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) {			printf ( "found !PXE at %x...", ptr );			if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {				printf ( "invalid checksum\n..." );				continue;			}			if ( ptr < get_free_base_memory() ) {				printf ( "in free base memory!\n\n"					 "WARNING: a valid !PXE structure was "					 "found in an area of memory marked "					 "as free!\n\n" );				undi.pxe = pxe;				pxe_dump();				undi.pxe = NULL;				printf ( "\nIgnoring and continuing, but this "					 "may cause problems later!\n\n" );				continue;			}			printf ( "ok\n" );			undi.pxe = pxe;			pxe_dump();			printf ( "Resetting pixie...\n" );			undi_unload_base_code();			eb_pxenv_stop_undi();			pxe_dump();			return 1;		}	}	printf ( "none found\n" );	ptr = 0;	return 0;}/* Locate PCI PnP ROMs. */int hunt_rom ( void ) {	static uint32_t ptr = 0;	printf ( "Hunting for ROMs..." );	if ( ptr == 0 ) ptr = 0x100000;	while ( ptr > 0x0c0000 ) {		ptr -= 0x800;		undi.rom = ( rom_t * ) phys_to_virt ( ptr );		if ( undi.rom->signature == ROM_SIGNATURE ) {			pcir_header_t *pcir_header = NULL;			pnp_header_t *pnp_header = NULL;			printf ( "found 55AA at %x...", ptr );			if ( undi.rom->pcir_off == 0 ) {				printf ( "not a PCI ROM\n..." );				continue;			}			pcir_header = (pcir_header_t*)( ( void * ) undi.rom +							undi.rom->pcir_off );			if ( pcir_header->signature != PCIR_SIGNATURE ) {				printf ( "invalid PCI signature\n..." );				continue;			}			printf ( "PCI:%hx:%hx...", pcir_header->vendor_id,				 pcir_header->device_id );			if ( ( pcir_header->vendor_id != undi.pci.vendor ) ||			     ( pcir_header->device_id != undi.pci.dev_id ) ) {				printf ( "not me (%hx:%hx)\n...",					 undi.pci.vendor,					 undi.pci.dev_id );				continue;			}			if ( undi.rom->pnp_off == 0 ) {				printf ( "not a PnP ROM\n..." );				continue;			}			pnp_header = (pnp_header_t*)( ( void * ) undi.rom +							 undi.rom->pnp_off );			if ( pnp_header->signature != PNP_SIGNATURE ) {				printf ( "invalid $PnP signature\n..." );				continue;			}			if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) {				printf ( "invalid PnP checksum\n..." );				continue;			}			printf ( "ok\nROM contains %s by %s\n",				 pnp_header->product_str_off==0 ? "(unknown)" :				 (void*)undi.rom+pnp_header->product_str_off,				 pnp_header->manuf_str_off==0 ? "(unknown)" :				 (void*)undi.rom+pnp_header->manuf_str_off );			return 1;		}	}	printf ( "none found\n" );	ptr = 0;	undi.rom = NULL;	return 0;}/* Locate ROMs containing UNDI drivers. */int hunt_undi_rom ( void ) {	while ( hunt_rom() ) {		if ( undi.rom->undi_rom_id_off == 0 ) {			printf ( "Not a PXE ROM\n" );			continue;		}		undi.undi_rom_id = (undi_rom_id_t *)			( (void *)undi.rom + undi.rom->undi_rom_id_off );		if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) {			printf ( "Invalid UNDI signature\n" );			continue;		}		printf ( "Located UNDI ROM supporting revision %d.%d.%d\n",			 undi.undi_rom_id->undi_rev[2],			 undi.undi_rom_id->undi_rev[1],			 undi.undi_rom_id->undi_rev[0] );		return 1;	}	return 0;}/************************************************************************** * Low-level UNDI API call wrappers **************************************************************************//* Make a real-mode UNDI API call to the UNDI routine at * routine_seg:routine_off, passing in three uint16 parameters on the * real-mode stack. * Calls the assembler wrapper routine __undi_call. */static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg,					uint16_t routine_off, uint16_t st0,					uint16_t st1, uint16_t st2 ) {	PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;	undi.undi_call_info->routine.segment = routine_seg;	undi.undi_call_info->routine.offset = routine_off;	undi.undi_call_info->stack[0] = st0;	undi.undi_call_info->stack[1] = st1;	undi.undi_call_info->stack[2] = st2;	ret = __undi_call ( SEGMENT( undi.undi_call_info ),			    OFFSET( undi.undi_call_info ) );	/* UNDI API calls may rudely change the status of A20 and not	 * bother to restore it afterwards.  Intel is known to be	 * guilty of this.	 *	 * Note that we will return to this point even if A20 gets	 * screwed up by the UNDI driver, because Etherboot always	 * resides in an even megabyte of RAM.	 */	gateA20_set();	return ret;}/* Make a real-mode call to the UNDI loader routine at * routine_seg:routine_off, passing in the seg:off address of a * pxenv_structure on the real-mode stack. */int undi_call_loader ( void ) {	PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;		pxenv_exit = _undi_call ( SEGMENT( undi.rom ),				  undi.undi_rom_id->undi_loader_off,				  OFFSET( undi.pxs ),				  SEGMENT( undi.pxs ),				  0 /* Unused for UNDI loader API */ );	/* Return 1 for success, to be consistent with other routines */	if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1;	printf ( "UNDI loader call failed with status %#hx\n",		 undi.pxs->Status );	return 0;}

⌨️ 快捷键说明

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