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