991c37869eb827c080bf5e15c052a2bd6ac30efc
[people/xl0/gpxe.git] / src / core / pxe_export.c
1 /* PXE API interface for Etherboot.
2  *
3  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 /* Tags used in this file:
21  *
22  * FIXME : obvious
23  * PXESPEC : question over interpretation of the PXE spec.
24  */
25
26 #ifdef PXE_EXPORT
27
28 #include "etherboot.h"
29 #include "pxe.h"
30 #include "pxe_export.h"
31 #include "pxe_callbacks.h"
32 #include "dev.h"
33 #include "nic.h"
34 #include "pci.h"
35 #include "cpu.h"
36 #include "timer.h"
37
38 #if TRACE_PXE
39 #define DBG(...) printf ( __VA_ARGS__ )
40 #else
41 #define DBG(...)
42 #endif
43
44 /* Not sure why this isn't a globally-used structure within Etherboot.
45  * (Because I didn't want to use packed to prevent gcc from aligning
46  * source however it liked. Also nstype is a u16, not a uint. - Ken)
47  */
48 typedef struct {
49         char dest[ETH_ALEN];
50         char source[ETH_ALEN];
51         unsigned int nstype;
52 } media_header_t;
53 static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
54
55 /* Global pointer to currently installed PXE stack */
56 pxe_stack_t *pxe_stack = NULL;
57
58 /* Various startup/shutdown routines.  The startup/shutdown call
59  * sequence is incredibly badly defined in the Intel PXE spec, for
60  * example:
61  *
62  *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
63  *   the adaptor should be those supplied to the most recent
64  *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
65  *
66  *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
67  *   available after making this call.  Figure 3-3 ("Early UNDI API
68  *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
69  *   call to the supposedly now unavailable PXENV_STOP_UNDI.
70  *
71  *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
72  *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
73  *   to PXENV_STOP_UNDI being made after the call to
74  *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
75  *   should have been freed (and, potentially, zeroed).
76  *
77  *   Nothing, anywhere, seems to mention who's responsible for freeing
78  *   up the base memory allocated for the stack segment.  It's not
79  *   even clear whether or not this is expected to be in free base
80  *   memory rather than claimed base memory.
81  *
82  * Consequently, we adopt a rather defensive strategy, designed to
83  * work with any conceivable sequence of initialisation or shutdown
84  * calls.  We have only two things that we care about:
85  *
86  *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
87  *   2. Is the NIC initialised?
88  *
89  * The NIC should never be initialised without the vectors being
90  * hooked, similarly the vectors should never be unhooked with the NIC
91  * still initialised.  We do, however, want to be able to have the
92  * vectors hooked with the NIC shutdown.  We therefore have three
93  * possible states:
94  *
95  *   1. Ready to unload: interrupts unhooked, NIC shutdown.
96  *   2. Midway: interrupts hooked, NIC shutdown.
97  *   3. Fully ready: interrupts hooked, NIC initialised.
98  *
99  * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
100  * these, and the call pxe_ensure_state() to ensure that the stack is
101  * in the specified state.  All our PXE API call implementations
102  * should use this call to ensure that the state is as required for
103  * that PXE API call.  This enables us to cope with whatever the
104  * end-user's interpretation of the PXE spec may be.  It even allows
105  * for someone calling e.g. PXENV_START_UNDI followed by
106  * PXENV_UDP_WRITE, without bothering with any of the intervening
107  * calls.
108  *
109  * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
110  * event of failure (which can arise from e.g. asking for state READY
111  * when we don't know where our NIC is), the error code
112  * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
113  * The macros ENSURE_XXX() can be used to achieve this without lots of
114  * duplicated code.
115  */
116
117 /* pxe_[un]hook_stack are architecture-specific and provided in
118  * pxe_callbacks.c
119  */
120
121 int pxe_initialise_nic ( void ) {
122         if ( pxe_stack->state >= READY ) return 1;
123
124 #warning "device probing mechanism has completely changed"
125 #if 0
126
127         /* Check if NIC is initialised.  dev.disable is set to 0
128          * when disable() is called, so we use this.
129          */
130         if ( dev.disable ) {
131                 /* NIC may have been initialised independently
132                  * (e.g. when we set up the stack prior to calling the
133                  * NBP).
134                  */
135                 pxe_stack->state = READY;
136                 return 1;
137         }
138
139         /* If we already have a NIC defined, reuse that one with
140          * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
141          * that one first.  Otherwise, set PROBE_FIRST.
142          */
143
144         if ( dev.state.pci.dev.use_specified == 1 ) {
145                 dev.how_probe = PROBE_NEXT;
146                 DBG ( " initialising NIC specified via START_UNDI" );
147         } else if ( dev.state.pci.dev.driver ) {
148                 DBG ( " reinitialising NIC" );
149                 dev.how_probe = PROBE_AWAKE;
150         } else {
151                 DBG ( " probing for any NIC" );
152                 dev.how_probe = PROBE_FIRST;
153         }
154
155         /* Call probe routine to bring up the NIC */
156         if ( eth_probe ( &dev ) != PROBE_WORKED ) {
157                 DBG ( " failed" );
158                 return 0;
159         }
160 #endif
161         
162
163         pxe_stack->state = READY;
164         return 1;
165 }
166
167 int pxe_shutdown_nic ( void ) {
168         if ( pxe_stack->state <= MIDWAY ) return 1;
169
170         eth_irq ( DISABLE );
171         eth_disable();
172         pxe_stack->state = MIDWAY;
173         return 1;
174 }
175
176 int ensure_pxe_state ( pxe_stack_state_t wanted ) {
177         int success = 1;
178
179         if ( ! pxe_stack ) return 0;
180         if ( wanted >= MIDWAY )
181                 success = success & hook_pxe_stack();
182         if ( wanted > MIDWAY ) {
183                 success = success & pxe_initialise_nic();
184         } else {
185                 success = success & pxe_shutdown_nic();
186         }
187         if ( wanted < MIDWAY )
188                 success = success & unhook_pxe_stack();
189         return success;
190 }
191
192 #define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
193                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
194                         return PXENV_EXIT_FAILURE; }
195 #define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
196                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
197                         return PXENV_EXIT_FAILURE; }
198 #define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
199                         structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
200                         return PXENV_EXIT_FAILURE; }
201
202 /*****************************************************************************
203  *
204  * Actual PXE API calls
205  *
206  *****************************************************************************/
207
208 /* PXENV_START_UNDI
209  *
210  * Status: working
211  */
212 PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI *start_undi ) {
213         unsigned char bus, devfn;
214
215         DBG ( "PXENV_START_UNDI" );
216         ENSURE_MIDWAY(start_undi);
217
218         /* Record PCI bus & devfn passed by caller, so we know which
219          * NIC they want to use.
220          *
221          * If they don't match our already-existing NIC structure, set
222          * values to ensure that the specified NIC is used at the next
223          * call to pxe_intialise_nic().
224          */
225         bus = ( start_undi->ax >> 8 ) & 0xff;
226         devfn = start_undi->ax & 0xff;
227
228 #warning "device probing mechanism has completely changed"
229 #if 0
230         if ( ( pci->dev.driver == NULL ) ||
231              ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
232                 /* This is quite a bit of a hack and relies on
233                  * knowledge of the internal operation of Etherboot's
234                  * probe mechanism.
235                  */
236                 DBG ( " set PCI %hhx:%hhx.%hhx",
237                       bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
238                 dev->type = BOOT_NIC;
239                 dev->to_probe = PROBE_PCI;
240                 memset ( &dev->state, 0, sizeof(dev->state) );
241                 pci->advance = 1;
242                 pci->dev.use_specified = 1;
243                 pci->dev.bus = bus;
244                 pci->dev.devfn = devfn;
245         }
246 #endif
247
248         start_undi->Status = PXENV_STATUS_SUCCESS;
249         return PXENV_EXIT_SUCCESS;
250 }
251
252 /* PXENV_UNDI_STARTUP
253  *
254  * Status: working
255  */
256 PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP *undi_startup ) {
257         DBG ( "PXENV_UNDI_STARTUP" );
258         ENSURE_MIDWAY(undi_startup);
259
260         undi_startup->Status = PXENV_STATUS_SUCCESS;
261         return PXENV_EXIT_SUCCESS;
262 }
263
264 /* PXENV_UNDI_CLEANUP
265  *
266  * Status: working
267  */
268 PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP *undi_cleanup ) {
269         DBG ( "PXENV_UNDI_CLEANUP" );
270         ENSURE_CAN_UNLOAD ( undi_cleanup );
271
272         undi_cleanup->Status = PXENV_STATUS_SUCCESS;
273         return PXENV_EXIT_SUCCESS;
274 }
275
276 /* PXENV_UNDI_INITIALIZE
277  *
278  * Status: working
279  */
280 PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE
281                                      *undi_initialize ) {
282         DBG ( "PXENV_UNDI_INITIALIZE" );
283         ENSURE_MIDWAY ( undi_initialize );
284
285         undi_initialize->Status = PXENV_STATUS_SUCCESS;
286         return PXENV_EXIT_SUCCESS;
287 }
288
289 /* PXENV_UNDI_RESET_ADAPTER
290  *
291  * Status: working
292  */
293 PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER
294                                         *undi_reset_adapter ) {
295         DBG ( "PXENV_UNDI_RESET_ADAPTER" );
296
297         ENSURE_MIDWAY ( undi_reset_adapter );
298         ENSURE_READY ( undi_reset_adapter );
299
300         undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
301         return PXENV_EXIT_SUCCESS;
302 }
303
304 /* PXENV_UNDI_SHUTDOWN
305  *
306  * Status: working
307  */
308 PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
309         DBG ( "PXENV_UNDI_SHUTDOWN" );
310         ENSURE_MIDWAY ( undi_shutdown );
311
312         undi_shutdown->Status = PXENV_STATUS_SUCCESS;
313         return PXENV_EXIT_SUCCESS;
314 }
315
316 /* PXENV_UNDI_OPEN
317  *
318  * Status: working
319  */
320 PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN *undi_open ) {
321         DBG ( "PXENV_UNDI_OPEN" );
322         ENSURE_READY ( undi_open );
323
324         /* PXESPEC: This is where we choose to enable interrupts.
325          * Can't actually find where we're meant to in the PXE spec,
326          * but this should work.
327          */
328         eth_irq ( ENABLE );
329
330         undi_open->Status = PXENV_STATUS_SUCCESS;
331         return PXENV_EXIT_SUCCESS;
332 }
333
334 /* PXENV_UNDI_CLOSE
335  *
336  * Status: working
337  */
338 PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE *undi_close ) {
339         DBG ( "PXENV_UNDI_CLOSE" );
340         ENSURE_MIDWAY ( undi_close );
341
342         undi_close->Status = PXENV_STATUS_SUCCESS;
343         return PXENV_EXIT_SUCCESS;
344 }
345
346 /* PXENV_UNDI_TRANSMIT
347  *
348  * Status: working
349  */
350 PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT *undi_transmit ) {
351         t_PXENV_UNDI_TBD *tbd;
352         const char *dest;
353         unsigned int type;
354         unsigned int length;
355         const char *data;
356         media_header_t *media_header;
357
358         DBG ( "PXENV_UNDI_TRANSMIT" );
359         ENSURE_READY ( undi_transmit );
360
361         /* We support only the "immediate" portion of the TBD.  Who
362          * knows what Intel's "engineers" were smoking when they came
363          * up with the array of transmit data blocks...
364          */
365         tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
366         if ( tbd->DataBlkCount > 0 ) {
367                 undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
368                 return PXENV_EXIT_FAILURE;
369         }
370         data = SEGOFF16_TO_PTR ( tbd->Xmit );
371         length = tbd->ImmedLength;
372
373         /* If destination is broadcast, we need to supply the MAC address */
374         if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
375                 dest = broadcast_mac;
376         } else {
377                 dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
378         }
379
380         /* We can't properly support P_UNKNOWN without rewriting all
381          * the driver transmit() methods, so we cheat: if P_UNKNOWN is
382          * specified we rip the destination address and type out of
383          * the pre-assembled packet, then skip over the header.
384          */
385         switch ( undi_transmit->Protocol ) {
386         case P_IP:      type = IP;      break;
387         case P_ARP:     type = ARP;     break;
388         case P_RARP:    type = RARP;    break;
389         case P_UNKNOWN:
390                 media_header = (media_header_t*)data;
391                 dest = media_header->dest;
392                 type = ntohs ( media_header->nstype );
393                 data += ETH_HLEN;
394                 length -= ETH_HLEN;
395                 break;
396         default:
397                 undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
398                 return PXENV_EXIT_FAILURE;
399         }
400
401         /* Send the packet */
402         eth_transmit ( dest, type, length, data );
403         
404         undi_transmit->Status = PXENV_STATUS_SUCCESS;
405         return PXENV_EXIT_SUCCESS;
406 }
407
408 /* PXENV_UNDI_SET_MCAST_ADDRESS
409  *
410  * Status: stub (no PXE multicast support)
411  */
412 PXENV_EXIT_t pxenv_undi_set_mcast_address ( t_PXENV_UNDI_SET_MCAST_ADDRESS
413                                             *undi_set_mcast_address ) {
414         DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
415         /* ENSURE_READY ( undi_set_mcast_address ); */
416         undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
417         return PXENV_EXIT_FAILURE;
418 }
419
420 /* PXENV_UNDI_SET_STATION_ADDRESS
421  *
422  * Status: working (deliberately incomplete)
423  */
424 PXENV_EXIT_t pxenv_undi_set_station_address ( t_PXENV_UNDI_SET_STATION_ADDRESS
425                                               *undi_set_station_address ) {
426         DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
427         ENSURE_READY ( undi_set_station_address );
428
429         /* We don't offer a facility to set the MAC address; this
430          * would require adding extra code to all the Etherboot
431          * drivers, for very little benefit.  If we're setting it to
432          * the current value anyway then return success, otherwise
433          * return UNSUPPORTED.
434          */
435         if ( memcmp ( nic->node_addr,
436                       &undi_set_station_address->StationAddress,
437                       ETH_ALEN ) == 0 ) {
438                 undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
439                 return PXENV_EXIT_SUCCESS;
440         }
441         undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
442         return PXENV_EXIT_FAILURE;
443 }
444
445 /* PXENV_UNDI_SET_PACKET_FILTER
446  *
447  * Status: won't implement (would require driver API changes for no
448  * real benefit)
449  */
450 PXENV_EXIT_t pxenv_undi_set_packet_filter ( t_PXENV_UNDI_SET_PACKET_FILTER
451                                             *undi_set_packet_filter ) {
452         DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
453         /* ENSURE_READY ( undi_set_packet_filter ); */
454         undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
455         return PXENV_EXIT_FAILURE;
456 }
457
458 /* PXENV_UNDI_GET_INFORMATION
459  *
460  * Status: working
461  */
462 PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
463                                           *undi_get_information ) {
464         DBG ( "PXENV_UNDI_GET_INFORMATION" );
465         ENSURE_READY ( undi_get_information );
466
467         undi_get_information->BaseIo = nic->ioaddr;
468         undi_get_information->IntNumber = nic->irqno;
469         /* Cheat: assume all cards can cope with this */
470         undi_get_information->MaxTranUnit = ETH_MAX_MTU;
471         /* Cheat: we only ever have Ethernet cards */
472         undi_get_information->HwType = ETHER_TYPE;
473         undi_get_information->HwAddrLen = ETH_ALEN;
474         /* Cheat: assume card is always configured with its permanent
475          * node address.  This is a valid assumption within Etherboot
476          * at the time of writing.
477          */
478         memcpy ( &undi_get_information->CurrentNodeAddress, nic->node_addr,
479                  ETH_ALEN );
480         memcpy ( &undi_get_information->PermNodeAddress, nic->node_addr,
481                  ETH_ALEN );
482         undi_get_information->ROMAddress = 0;
483                 /* nic->rom_info->rom_segment; */
484         /* We only provide the ability to receive or transmit a single
485          * packet at a time.  This is a bootloader, not an OS.
486          */
487         undi_get_information->RxBufCt = 1;
488         undi_get_information->TxBufCt = 1;
489         undi_get_information->Status = PXENV_STATUS_SUCCESS;
490         return PXENV_EXIT_SUCCESS;
491 }
492
493 /* PXENV_UNDI_GET_STATISTICS
494  *
495  * Status: won't implement (would require driver API changes for no
496  * real benefit)
497  */
498 PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS
499                                          *undi_get_statistics ) {
500         DBG ( "PXENV_UNDI_GET_STATISTICS" );
501         /* ENSURE_READY ( undi_get_statistics ); */
502         undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
503         return PXENV_EXIT_FAILURE;
504 }
505
506 /* PXENV_UNDI_CLEAR_STATISTICS
507  *
508  * Status: won't implement (would require driver API changes for no
509  * real benefit)
510  */
511 PXENV_EXIT_t pxenv_undi_clear_statistics ( t_PXENV_UNDI_CLEAR_STATISTICS
512                                            *undi_clear_statistics ) {
513         DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
514         /* ENSURE_READY ( undi_clear_statistics ); */
515         undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
516         return PXENV_EXIT_FAILURE;
517 }
518
519 /* PXENV_UNDI_INITIATE_DIAGS
520  *
521  * Status: won't implement (would require driver API changes for no
522  * real benefit)
523  */
524 PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS
525                                          *undi_initiate_diags ) {
526         DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
527         /* ENSURE_READY ( undi_initiate_diags ); */
528         undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
529         return PXENV_EXIT_FAILURE;
530 }
531
532 /* PXENV_UNDI_FORCE_INTERRUPT
533  *
534  * Status: working
535  */
536 PXENV_EXIT_t pxenv_undi_force_interrupt ( t_PXENV_UNDI_FORCE_INTERRUPT
537                                           *undi_force_interrupt ) {
538         DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
539         ENSURE_READY ( undi_force_interrupt );
540
541         eth_irq ( FORCE );
542         undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
543         return PXENV_EXIT_SUCCESS;
544 }
545
546 /* PXENV_UNDI_GET_MCAST_ADDRESS
547  *
548  * Status: stub (no PXE multicast support)
549  */
550 PXENV_EXIT_t pxenv_undi_get_mcast_address ( t_PXENV_UNDI_GET_MCAST_ADDRESS
551                                             *undi_get_mcast_address ) {
552         DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
553         /* ENSURE_READY ( undi_get_mcast_address ); */
554         undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
555         return PXENV_EXIT_FAILURE;
556 }
557
558 /* PXENV_UNDI_GET_NIC_TYPE
559  *
560  * Status: working
561  */
562 PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE
563                                        *undi_get_nic_type ) {
564 #warning "device probing mechanism has changed completely"
565
566 #if 0
567         struct dev *dev = &dev;
568         
569         DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
570         ENSURE_READY ( undi_get_nic_type );
571         
572         if ( dev->to_probe == PROBE_PCI ) {
573                 struct pci_device *pci = &dev->state.pci.dev;
574
575                 undi_get_nic_type->NicType = PCI_NIC;
576                 undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
577                 undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
578                 undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
579                 undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
580                 undi_get_nic_type->info.pci.BusDevFunc =
581                         ( pci->bus << 8 ) | pci->devfn;
582                 /* Cheat: these fields are probably unnecessary, and
583                  * would require adding extra code to pci.c.
584                  */
585                 undi_get_nic_type->info.pci.Prog_Intf = 0;
586                 undi_get_nic_type->info.pci.Rev = 0;
587                 undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
588                 undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
589         } else if ( dev->to_probe == PROBE_ISA ) {
590                 /* const struct isa_driver *isa = dev->state.isa.driver; */
591
592                 undi_get_nic_type->NicType = PnP_NIC;
593                 /* Don't think anything fills these fields in, and
594                  * probably no-one will ever be interested in them.
595                  */
596                 undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
597                 undi_get_nic_type->info.pnp.Base_Class = 0;
598                 undi_get_nic_type->info.pnp.Sub_Class = 0;
599                 undi_get_nic_type->info.pnp.Prog_Intf = 0;
600                 undi_get_nic_type->info.pnp.CardSelNum = 0;
601         } else {
602                 /* PXESPEC: There doesn't seem to be an "unknown type"
603                  * defined.
604                  */
605                 undi_get_nic_type->NicType = 0;
606         }
607         undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
608         return PXENV_EXIT_SUCCESS;
609
610 #endif
611 }
612
613 /* PXENV_UNDI_GET_IFACE_INFO
614  *
615  * Status: working
616  */
617 PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO
618                                          *undi_get_iface_info ) {
619         DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
620         ENSURE_READY ( undi_get_iface_info );
621
622         /* Just hand back some info, doesn't really matter what it is.
623          * Most PXE stacks seem to take this approach.
624          */
625         sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
626         undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
627         undi_get_iface_info->ServiceFlags = 0;
628         memset ( undi_get_iface_info->Reserved, 0,
629                  sizeof(undi_get_iface_info->Reserved) );
630         undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
631         return PXENV_EXIT_SUCCESS;
632 }
633
634 /* PXENV_UNDI_ISR
635  *
636  * Status: working
637  */
638 PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
639         media_header_t *media_header = (media_header_t*)nic->packet;
640
641         DBG ( "PXENV_UNDI_ISR" );
642         /* We can't call ENSURE_READY, because this could be being
643          * called as part of an interrupt service routine.  Instead,
644          * we should simply die if we're not READY.
645          */
646         if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
647                 undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
648                 return PXENV_EXIT_FAILURE;
649         }
650         
651         /* Just in case some idiot actually looks at these fields when
652          * we weren't meant to fill them in...
653          */
654         undi_isr->BufferLength = 0;
655         undi_isr->FrameLength = 0;
656         undi_isr->FrameHeaderLength = 0;
657         undi_isr->ProtType = 0;
658         undi_isr->PktType = 0;
659
660         switch ( undi_isr->FuncFlag ) {
661         case PXENV_UNDI_ISR_IN_START :
662                 /* Is there a packet waiting?  If so, disable
663                  * interrupts on the NIC and return "it's ours".  Do
664                  * *not* necessarily acknowledge the interrupt; this
665                  * can happen later when eth_poll(1) is called.  As
666                  * long as the interrupt is masked off so that it
667                  * doesn't immediately retrigger the 8259A then all
668                  * should be well.
669                  */
670                 DBG ( " START" );
671                 if ( eth_poll ( 0 ) ) {
672                         DBG ( " OURS" );
673                         eth_irq ( DISABLE );
674                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
675                 } else {
676                         DBG ( " NOT_OURS" );
677                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
678                 }
679                 break;
680         case PXENV_UNDI_ISR_IN_PROCESS :
681                 /* Call poll(), return packet.  If no packet, return "done".
682                  */
683                 DBG ( " PROCESS" );
684                 if ( eth_poll ( 1 ) ) {
685                         DBG ( " RECEIVE %d", nic->packetlen );
686                         if ( nic->packetlen > sizeof(pxe_stack->packet) ) {
687                                 /* Should never happen */
688                                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
689                                 undi_isr->Status =
690                                         PXENV_STATUS_OUT_OF_RESOURCES;
691                                 return PXENV_EXIT_FAILURE;
692                         }
693                         undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
694                         undi_isr->BufferLength = nic->packetlen;
695                         undi_isr->FrameLength = nic->packetlen;
696                         undi_isr->FrameHeaderLength = ETH_HLEN;
697                         memcpy ( pxe_stack->packet, nic->packet, nic->packetlen);
698                         PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
699                         switch ( ntohs(media_header->nstype) ) {
700                         case IP :       undi_isr->ProtType = P_IP;      break;
701                         case ARP :      undi_isr->ProtType = P_ARP;     break;
702                         case RARP :     undi_isr->ProtType = P_RARP;    break;
703                         default :       undi_isr->ProtType = P_UNKNOWN;
704                         }
705                         if ( memcmp ( media_header->dest, broadcast_mac,
706                                       sizeof(broadcast_mac) ) ) {
707                                 undi_isr->PktType = XMT_BROADCAST;
708                         } else {
709                                 undi_isr->PktType = XMT_DESTADDR;
710                         }
711                         break;
712                 } else {
713                         /* No break - fall through to IN_GET_NEXT */
714                 }
715         case PXENV_UNDI_ISR_IN_GET_NEXT :
716                 /* We only ever return one frame at a time */
717                 DBG ( " GET_NEXT DONE" );
718                 /* Re-enable interrupts */
719                 eth_irq ( ENABLE );
720                 /* Force an interrupt if there's a packet still
721                  * waiting, since we only handle one packet per
722                  * interrupt.
723                  */
724                 if ( eth_poll ( 0 ) ) {
725                         DBG ( " (RETRIGGER)" );
726                         eth_irq ( FORCE );
727                 }
728                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
729                 break;
730         default :
731                 /* Should never happen */
732                 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
733                 undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
734                 return PXENV_EXIT_FAILURE;
735         }
736
737         undi_isr->Status = PXENV_STATUS_SUCCESS;
738         return PXENV_EXIT_SUCCESS;
739 }
740
741 /* PXENV_STOP_UNDI
742  *
743  * Status: working
744  */
745 PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI *stop_undi ) {
746         DBG ( "PXENV_STOP_UNDI" );
747
748         if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
749                 stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
750                 return PXENV_EXIT_FAILURE;
751         }
752
753         stop_undi->Status = PXENV_STATUS_SUCCESS;
754         return PXENV_EXIT_SUCCESS;
755 }
756
757 /* PXENV_TFTP_OPEN
758  *
759  * Status: working
760  */
761 PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN *tftp_open ) {
762         struct tftpreq_info_t request;
763         struct tftpblk_info_t block;
764
765         DBG ( "PXENV_TFTP_OPEN" );
766         ENSURE_READY ( tftp_open );
767
768         /* Change server address if different */
769         if ( tftp_open->ServerIPAddress && 
770              tftp_open->ServerIPAddress!=arptable[ARP_SERVER].ipaddr.s_addr ) {
771                 memset(arptable[ARP_SERVER].node, 0, ETH_ALEN ); /* kill arp */
772                 arptable[ARP_SERVER].ipaddr.s_addr=tftp_open->ServerIPAddress;
773         }
774         /* Ignore gateway address; we can route properly */
775         /* Fill in request structure */
776         request.name = tftp_open->FileName;
777         request.port = ntohs(tftp_open->TFTPPort);
778 #ifdef WORK_AROUND_BPBATCH_BUG        
779         /* Force use of port 69; BpBatch tries to use port 4 for some         
780         * bizarre reason.         */        
781         request.port = TFTP_PORT;
782 #endif
783         request.blksize = tftp_open->PacketSize;
784         DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
785               request.port, request.name, request.blksize );
786         if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
787         /* Make request and get first packet */
788         if ( !tftp_block ( &request, &block ) ) {
789                 tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
790                 return PXENV_EXIT_FAILURE;
791         }
792         /* Fill in PacketSize */
793         tftp_open->PacketSize = request.blksize;
794         /* Store first block for later retrieval by TFTP_READ */
795         pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
796         pxe_stack->tftpdata.len = block.len;
797         pxe_stack->tftpdata.eof = block.eof;
798         memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
799
800         tftp_open->Status = PXENV_STATUS_SUCCESS;
801         return PXENV_EXIT_SUCCESS;
802 }
803
804 /* PXENV_TFTP_CLOSE
805  *
806  * Status: working
807  */
808 PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE *tftp_close ) {
809         DBG ( "PXENV_TFTP_CLOSE" );
810         ENSURE_READY ( tftp_close );
811         tftp_close->Status = PXENV_STATUS_SUCCESS;
812         return PXENV_EXIT_SUCCESS;
813 }
814
815 /* PXENV_TFTP_READ
816  *
817  * Status: working
818  */
819 PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ *tftp_read ) {
820         struct tftpblk_info_t block;
821
822         DBG ( "PXENV_TFTP_READ" );
823         ENSURE_READY ( tftp_read );
824
825         /* Do we have a block pending */
826         if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
827                 block.data = pxe_stack->tftpdata.data;
828                 block.len = pxe_stack->tftpdata.len;
829                 block.eof = pxe_stack->tftpdata.eof;
830                 block.block = 1; /* Will be the first block */
831                 pxe_stack->tftpdata.magic_cookie = 0;
832         } else {
833                 if ( !tftp_block ( NULL, &block ) ) {
834                         tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
835                         return PXENV_EXIT_FAILURE;
836                 }
837         }
838
839         /* Return data */
840         tftp_read->PacketNumber = block.block;
841         tftp_read->BufferSize = block.len;
842         memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
843         DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
844               tftp_read->Buffer.offset );
845  
846         tftp_read->Status = PXENV_STATUS_SUCCESS;
847         return PXENV_EXIT_SUCCESS;
848 }
849
850 /* PXENV_TFTP_READ_FILE
851  *
852  * Status: working
853  */
854
855 int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused, unsigned int len, int eof ) {
856         if ( pxe_stack->readfile.buffer ) {
857                 if ( pxe_stack->readfile.offset + len >=
858                      pxe_stack->readfile.bufferlen ) return -1;
859                 memcpy ( pxe_stack->readfile.buffer +
860                          pxe_stack->readfile.offset, data, len );
861         }
862         pxe_stack->readfile.offset += len;
863         return eof ? 0 : 1;
864 }
865
866 PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE *tftp_read_file ) {
867         int rc;
868
869         DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
870               tftp_read_file->Buffer, tftp_read_file->Buffer + tftp_read_file->BufferSize );
871         ENSURE_READY ( tftp_read_file );
872
873         /* inserted by Klaus Wittemeier */
874         /* KERNEL_BUF stores the name of the last required file */
875         /* This is a fix to make Microsoft Remote Install Services work (RIS) */
876         memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
877         /* end of insertion */
878
879         pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
880         pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
881         pxe_stack->readfile.offset = 0;
882
883         rc = tftp ( tftp_read_file->FileName, pxe_tftp_read_block );
884         if ( rc ) {
885                 tftp_read_file->Status = PXENV_STATUS_FAILURE;
886                 return PXENV_EXIT_FAILURE;
887         }
888         tftp_read_file->Status = PXENV_STATUS_SUCCESS;
889         return PXENV_EXIT_SUCCESS;
890 }
891
892 /* PXENV_TFTP_GET_FSIZE
893  *
894  * Status: working, though ugly (we actually read the whole file,
895  * because it's too ugly to make Etherboot request the tsize option
896  * and hand it to us).
897  */
898 PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE *tftp_get_fsize ) {
899         int rc;
900
901         DBG ( "PXENV_TFTP_GET_FSIZE" );
902         ENSURE_READY ( tftp_get_fsize );
903
904         pxe_stack->readfile.buffer = NULL;
905         pxe_stack->readfile.bufferlen = 0;
906         pxe_stack->readfile.offset = 0;
907
908         rc = tftp ( tftp_get_fsize->FileName, pxe_tftp_read_block );
909         if ( rc ) {
910                 tftp_get_fsize->FileSize = 0;
911                 tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
912                 return PXENV_EXIT_FAILURE;
913         }
914         tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
915         tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
916         return PXENV_EXIT_SUCCESS;
917 }
918
919 /* PXENV_UDP_OPEN
920  *
921  * Status: working
922  */
923 PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN *udp_open ) {
924         DBG ( "PXENV_UDP_OPEN" );
925         ENSURE_READY ( udp_open );
926
927         if ( udp_open->src_ip &&
928              udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
929                 /* Overwrite our IP address */
930                 DBG ( " with new IP %@", udp_open->src_ip );
931                 arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
932         }
933
934         udp_open->Status = PXENV_STATUS_SUCCESS;
935         return PXENV_EXIT_SUCCESS;
936 }
937
938 /* PXENV_UDP_CLOSE
939  *
940  * Status: working
941  */
942 PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE *udp_close ) {
943         DBG ( "PXENV_UDP_CLOSE" );
944         ENSURE_READY ( udp_close );
945         udp_close->Status = PXENV_STATUS_SUCCESS;
946         return PXENV_EXIT_SUCCESS;
947 }
948
949 /* PXENV_UDP_READ
950  *
951  * Status: working
952  */
953 int await_pxe_udp ( int ival __unused, void *ptr,
954                     unsigned short ptype __unused,
955                     struct iphdr *ip, struct udphdr *udp,
956                     struct tcphdr *tcp __unused ) {
957         t_PXENV_UDP_READ *udp_read = (t_PXENV_UDP_READ*)ptr;
958         uint16_t d_port;
959         size_t size;
960
961         /* Ignore non-UDP packets */
962         if ( !udp ) {
963                 DBG ( " non-UDP" );
964                 return 0;
965         }
966         
967         /* Check dest_ip */
968         if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
969                 DBG ( " wrong dest IP (got %@, wanted %@)",
970                       ip->dest.s_addr, udp_read->dest_ip );
971                 return 0;
972         }
973
974         /* Check dest_port */
975         d_port = ntohs ( udp_read->d_port );
976         if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
977                 DBG ( " wrong dest port (got %d, wanted %d)",
978                       ntohs(udp->dest), d_port );
979                 return 0;
980         }
981
982         /* Copy packet to buffer and fill in information */
983         udp_read->src_ip = ip->src.s_addr;
984         udp_read->s_port = udp->src; /* Both in network order */
985         size = ntohs(udp->len) - sizeof(*udp);
986         /* Workaround: NTLDR expects us to fill these in, even though
987          * PXESPEC clearly defines them as input parameters.
988          */
989         udp_read->dest_ip = ip->dest.s_addr;
990         udp_read->d_port = udp->dest;
991         DBG ( " %@:%d->%@:%d (%d)",
992               udp_read->src_ip, ntohs(udp_read->s_port),
993               udp_read->dest_ip, ntohs(udp_read->d_port), size );
994         if ( udp_read->buffer_size < size ) {
995                 /* PXESPEC: what error code should we actually return? */
996                 DBG ( " buffer too small (%d)", udp_read->buffer_size );
997                 udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
998                 return 0;
999         }
1000         memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
1001         udp_read->buffer_size = size;
1002
1003         return 1;
1004 }
1005
1006 PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ *udp_read ) {
1007         DBG ( "PXENV_UDP_READ" );
1008         ENSURE_READY ( udp_read );
1009
1010         /* Use await_reply with a timeout of zero */
1011         /* Allow await_reply to change Status if necessary */
1012         udp_read->Status = PXENV_STATUS_FAILURE;
1013         if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
1014                 return PXENV_EXIT_FAILURE;
1015         }
1016
1017         udp_read->Status = PXENV_STATUS_SUCCESS;
1018         return PXENV_EXIT_SUCCESS;
1019 }
1020
1021 /* PXENV_UDP_WRITE
1022  *
1023  * Status: working
1024  */
1025 PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE *udp_write ) {
1026         uint16_t src_port;
1027         uint16_t dst_port;
1028         struct udppacket *packet = (struct udppacket *)nic->packet;
1029         int packet_size;
1030
1031         DBG ( "PXENV_UDP_WRITE" );
1032         ENSURE_READY ( udp_write );
1033
1034         /* PXE spec says source port is 2069 if not specified */
1035         src_port = ntohs(udp_write->src_port);
1036         if ( src_port == 0 ) src_port = 2069;
1037         dst_port = ntohs(udp_write->dst_port);
1038         DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
1039               udp_write->buffer_size );
1040         
1041         /* FIXME: we ignore the gateway specified, since we're
1042          * confident of being able to do our own routing.  We should
1043          * probably allow for multiple gateways.
1044          */
1045         
1046         /* Copy payload to packet buffer */
1047         packet_size = ( (void*)&packet->payload - (void*)packet )
1048                 + udp_write->buffer_size;
1049         if ( packet_size > ETH_FRAME_LEN ) {
1050                 udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
1051                 return PXENV_EXIT_FAILURE;
1052         }
1053         memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
1054                  udp_write->buffer_size );
1055
1056         /* Transmit packet */
1057         if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
1058                               packet_size, packet ) ) {
1059                 udp_write->Status = PXENV_STATUS_FAILURE;
1060                 return PXENV_EXIT_FAILURE;
1061         }
1062
1063         udp_write->Status = PXENV_STATUS_SUCCESS;
1064         return PXENV_EXIT_SUCCESS;
1065 }
1066
1067 /* PXENV_UNLOAD_STACK
1068  *
1069  * Status: working
1070  */
1071 PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK *unload_stack ) {
1072         int success;
1073
1074         DBG ( "PXENV_UNLOAD_STACK" );
1075         success = ensure_pxe_state ( CAN_UNLOAD );
1076
1077         /* We need to call cleanup() at some point.  The network card
1078          * has already been disabled by ENSURE_CAN_UNLOAD(), but for
1079          * the sake of completeness we should call the console_fini()
1080          * etc. that are part of cleanup().
1081          *
1082          * There seems to be a lack of consensus on which is the final
1083          * PXE API call to make, but it's a fairly safe bet that all
1084          * the potential shutdown sequences will include a call to
1085          * PXENV_UNLOAD_STACK at some point, so we may as well do it
1086          * here.
1087          */
1088         cleanup();
1089
1090         if ( ! success ) {
1091                 unload_stack->Status = PXENV_STATUS_KEEP_ALL;
1092                 return PXENV_EXIT_FAILURE;
1093         }
1094
1095         unload_stack->Status = PXENV_STATUS_SUCCESS;
1096         return PXENV_EXIT_SUCCESS;
1097 }
1098
1099 /* PXENV_GET_CACHED_INFO
1100  *
1101  * Status: working
1102  */
1103 PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO
1104                                      *get_cached_info ) {
1105         BOOTPLAYER *cached_info = &pxe_stack->cached_info;
1106         DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
1107         ENSURE_READY ( get_cached_info );
1108
1109         /* Fill in cached_info structure in our pxe_stack */
1110
1111         /* I don't think there's actually any way we can be called in
1112          * the middle of a DHCP request... 
1113          */
1114         cached_info->opcode = BOOTP_REP;
1115         /* We only have Ethernet drivers */
1116         cached_info->Hardware = ETHER_TYPE;
1117         cached_info->Hardlen = ETH_ALEN;
1118         /* PXESPEC: "Client sets" says the spec, but who's filling in
1119          * this structure?  It ain't the client.
1120          */
1121         cached_info->Gatehops = 0;
1122         cached_info->ident = 0;
1123         cached_info->seconds = 0;
1124         cached_info->Flags = BOOTP_BCAST;
1125         /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
1126         cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
1127         cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
1128         cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
1129         /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
1130         cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
1131         memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
1132         /* Nullify server name */
1133         cached_info->Sname[0] = '\0';
1134         memcpy ( cached_info->bootfile, KERNEL_BUF,
1135                  sizeof(cached_info->bootfile) );
1136         /* Copy DHCP vendor options */
1137         memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
1138                  sizeof(cached_info->vendor.d) );
1139         
1140         /* Copy to user-specified buffer, or set pointer to our buffer */
1141         get_cached_info->BufferLimit = sizeof(*cached_info);
1142         /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
1143          * 0, but what are we supposed to do with a null buffer of
1144          * non-zero size?!
1145          */
1146         if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
1147                 /* Point back to our buffer */
1148                 PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
1149                 get_cached_info->BufferSize = sizeof(*cached_info);
1150         } else {
1151                 /* Copy to user buffer */
1152                 size_t size = sizeof(*cached_info);
1153                 void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
1154                 if ( get_cached_info->BufferSize < size )
1155                         size = get_cached_info->BufferSize;
1156                 DBG ( " to %x", virt_to_phys ( buffer ) );
1157                 memcpy ( buffer, cached_info, size );
1158                 /* PXESPEC: Should we return an error if the user
1159                  * buffer is too small?  We do return the actual size
1160                  * of the buffer via BufferLimit, so the user does
1161                  * have a way to detect this already.
1162                  */
1163         }
1164
1165         get_cached_info->Status = PXENV_STATUS_SUCCESS;
1166         return PXENV_EXIT_SUCCESS;
1167 }
1168
1169 /* PXENV_RESTART_TFTP
1170  *
1171  * Status: working
1172  */
1173 PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP *restart_tftp ) {
1174         PXENV_EXIT_t tftp_exit;
1175
1176         DBG ( "PXENV_RESTART_TFTP" );
1177         ENSURE_READY ( restart_tftp );
1178
1179         /* Words cannot describe the complete mismatch between the PXE
1180          * specification and any possible version of reality...
1181          */
1182         restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
1183         restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
1184         DBG ( "(" );
1185         tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (t_PXENV_ANY*)restart_tftp );
1186         DBG ( ")" );
1187         if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
1188
1189         /* Fire up the new NBP */
1190         restart_tftp->Status = xstartpxe();
1191
1192         /* Not sure what "SUCCESS" actually means, since we can only
1193          * return if the new NBP failed to boot...
1194          */
1195         return PXENV_EXIT_SUCCESS;
1196 }
1197
1198 /* PXENV_START_BASE
1199  *
1200  * Status: won't implement (requires major structural changes)
1201  */
1202 PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE *start_base ) {
1203         DBG ( "PXENV_START_BASE" );
1204         /* ENSURE_READY ( start_base ); */
1205         start_base->Status = PXENV_STATUS_UNSUPPORTED;
1206         return PXENV_EXIT_FAILURE;
1207 }
1208
1209 /* PXENV_STOP_BASE
1210  *
1211  * Status: working
1212  */
1213 PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE *stop_base ) {
1214         DBG ( "PXENV_STOP_BASE" );
1215
1216         /* The only time we will be called is when the NBP is trying
1217          * to shut down the PXE stack.  There's nothing we need to do
1218          * in this call.
1219          */
1220
1221         stop_base->Status = PXENV_STATUS_SUCCESS;
1222         return PXENV_EXIT_SUCCESS;
1223 }
1224
1225 /* PXENV_UNDI_LOADER
1226  *
1227  * Status: working
1228  *
1229  * NOTE: This is not a genuine PXE API call; the loader has a separate
1230  * entry point.  However, to simplify the mapping of the PXE API to
1231  * the internal Etherboot API, both are directed through the same
1232  * interface.
1233  */
1234 PXENV_EXIT_t pxenv_undi_loader ( undi_loader_t *loader ) {
1235         uint32_t loader_phys = virt_to_phys ( loader );
1236
1237         DBG ( "PXENV_UNDI_LOADER" );
1238         
1239         /* Set UNDI DS as our real-mode stack */
1240         use_undi_ds_for_rm_stack ( loader->undi_ds );
1241
1242         /* FIXME: These lines are borrowed from main.c.  There should
1243          * probably be a single initialise() function that does all
1244          * this, but it's currently split interestingly between main()
1245          * and main_loop()...
1246          */
1247
1248
1249         /* CHECKME: Our init functions have probably already been
1250            called by the ROM prefix's call to setup(), haven't
1251            they? */
1252
1253
1254
1255         /* We have relocated; the loader pointer is now invalid */
1256         loader = phys_to_virt ( loader_phys );
1257
1258         /* Install PXE stack to area specified by NBP */
1259         install_pxe_stack ( VIRTUAL ( loader->undi_cs, 0 ) );
1260         
1261         /* Call pxenv_start_undi to set parameters.  Why the hell PXE
1262          * requires these parameters to be provided twice is beyond
1263          * the wit of any sane man.  Don't worry if it fails; the NBP
1264          * should call PXENV_START_UNDI separately anyway.
1265          */
1266         pxenv_start_undi ( &loader->start_undi );
1267         /* Unhook stack; the loader is not meant to hook int 1a etc,
1268          * but the call the pxenv_start_undi will cause it to happen.
1269          */
1270         ENSURE_CAN_UNLOAD ( loader );
1271
1272         /* Fill in addresses of !PXE and PXENV+ structures */
1273         PTR_TO_SEGOFF16 ( &pxe_stack->pxe, loader->pxe_ptr );
1274         PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, loader->pxenv_ptr );
1275         
1276         loader->Status = PXENV_STATUS_SUCCESS;
1277         return PXENV_EXIT_SUCCESS;
1278 }
1279
1280 /* API call dispatcher
1281  *
1282  * Status: complete
1283  */
1284 PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params ) {
1285         PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
1286
1287         /* Set default status in case child routine fails to do so */
1288         params->Status = PXENV_STATUS_FAILURE;
1289
1290         DBG ( "[" );
1291
1292         /* Hand off to relevant API routine */
1293         switch ( opcode ) {
1294         case PXENV_START_UNDI:
1295                 ret = pxenv_start_undi ( &params->start_undi );
1296                 break;
1297         case PXENV_UNDI_STARTUP:
1298                 ret = pxenv_undi_startup ( &params->undi_startup );
1299                 break;
1300         case PXENV_UNDI_CLEANUP:
1301                 ret = pxenv_undi_cleanup ( &params->undi_cleanup );
1302                 break;
1303         case PXENV_UNDI_INITIALIZE:
1304                 ret = pxenv_undi_initialize ( &params->undi_initialize );
1305                 break;
1306         case PXENV_UNDI_RESET_ADAPTER:
1307                 ret = pxenv_undi_reset_adapter ( &params->undi_reset_adapter );
1308                 break;
1309         case PXENV_UNDI_SHUTDOWN:
1310                 ret = pxenv_undi_shutdown ( &params->undi_shutdown );
1311                 break;
1312         case PXENV_UNDI_OPEN:
1313                 ret = pxenv_undi_open ( &params->undi_open );
1314                 break;
1315         case PXENV_UNDI_CLOSE:
1316                 ret = pxenv_undi_close ( &params->undi_close );
1317                 break;
1318         case PXENV_UNDI_TRANSMIT:
1319                 ret = pxenv_undi_transmit ( &params->undi_transmit );
1320                 break;
1321         case PXENV_UNDI_SET_MCAST_ADDRESS:
1322                 ret = pxenv_undi_set_mcast_address (
1323                                              &params->undi_set_mcast_address );
1324                 break;
1325         case PXENV_UNDI_SET_STATION_ADDRESS:
1326                 ret = pxenv_undi_set_station_address (
1327                                            &params->undi_set_station_address );
1328                 break;
1329         case PXENV_UNDI_SET_PACKET_FILTER:
1330                 ret = pxenv_undi_set_packet_filter (
1331                                              &params->undi_set_packet_filter );
1332                 break;
1333         case PXENV_UNDI_GET_INFORMATION:
1334                 ret = pxenv_undi_get_information (
1335                                                &params->undi_get_information );
1336                 break;
1337         case PXENV_UNDI_GET_STATISTICS:
1338                 ret = pxenv_undi_get_statistics (
1339                                                 &params->undi_get_statistics );
1340                 break;
1341         case PXENV_UNDI_CLEAR_STATISTICS:
1342                 ret = pxenv_undi_clear_statistics (
1343                                               &params->undi_clear_statistics );
1344                 break;
1345         case PXENV_UNDI_INITIATE_DIAGS:
1346                 ret = pxenv_undi_initiate_diags (
1347                                                 &params->undi_initiate_diags );
1348                 break;
1349         case PXENV_UNDI_FORCE_INTERRUPT:
1350                 ret = pxenv_undi_force_interrupt (
1351                                                &params->undi_force_interrupt );
1352                 break;
1353         case PXENV_UNDI_GET_MCAST_ADDRESS:
1354                 ret = pxenv_undi_get_mcast_address (
1355                                              &params->undi_get_mcast_address );
1356                 break;
1357         case PXENV_UNDI_GET_NIC_TYPE:
1358                 ret = pxenv_undi_get_nic_type ( &params->undi_get_nic_type );
1359                 break;
1360         case PXENV_UNDI_GET_IFACE_INFO:
1361                 ret = pxenv_undi_get_iface_info (
1362                                                 &params->undi_get_iface_info );
1363                 break;
1364         case PXENV_UNDI_ISR:
1365                 ret = pxenv_undi_isr ( &params->undi_isr );
1366                 break;
1367         case PXENV_STOP_UNDI:
1368                 ret = pxenv_stop_undi ( &params->stop_undi );
1369                 break;
1370         case PXENV_TFTP_OPEN:
1371                 ret = pxenv_tftp_open ( &params->tftp_open );
1372                 break;
1373         case PXENV_TFTP_CLOSE:
1374                 ret = pxenv_tftp_close ( &params->tftp_close );
1375                 break;
1376         case PXENV_TFTP_READ:
1377                 ret = pxenv_tftp_read ( &params->tftp_read );
1378                 break;
1379         case PXENV_TFTP_READ_FILE:
1380                 ret = pxenv_tftp_read_file ( &params->tftp_read_file );
1381                 break;
1382         case PXENV_TFTP_GET_FSIZE:
1383                 ret = pxenv_tftp_get_fsize ( &params->tftp_get_fsize );
1384                 break;
1385         case PXENV_UDP_OPEN:
1386                 ret = pxenv_udp_open ( &params->udp_open );
1387                 break;
1388         case PXENV_UDP_CLOSE:
1389                 ret = pxenv_udp_close ( &params->udp_close );
1390                 break;
1391         case PXENV_UDP_READ:
1392                 ret = pxenv_udp_read ( &params->udp_read );
1393                 break;
1394         case PXENV_UDP_WRITE:
1395                 ret = pxenv_udp_write ( &params->udp_write );
1396                 break;
1397         case PXENV_UNLOAD_STACK:
1398                 ret = pxenv_unload_stack ( &params->unload_stack );
1399                 break;
1400         case PXENV_GET_CACHED_INFO:
1401                 ret = pxenv_get_cached_info ( &params->get_cached_info );
1402                 break;
1403         case PXENV_RESTART_TFTP:
1404                 ret = pxenv_restart_tftp ( &params->restart_tftp );
1405                 break;
1406         case PXENV_START_BASE:
1407                 ret = pxenv_start_base ( &params->start_base );
1408                 break;
1409         case PXENV_STOP_BASE:
1410                 ret = pxenv_stop_base ( &params->stop_base );
1411                 break;
1412         case PXENV_UNDI_LOADER:
1413                 ret = pxenv_undi_loader ( &params->loader );
1414                 break;
1415                 
1416         default:
1417                 DBG ( "PXENV_UNKNOWN_%hx", opcode );
1418                 params->Status = PXENV_STATUS_UNSUPPORTED;
1419                 ret = PXENV_EXIT_FAILURE;
1420                 break;
1421         }
1422
1423         if ( params->Status != PXENV_STATUS_SUCCESS ) {
1424                 DBG ( " %hx", params->Status );
1425         }
1426         if ( ret != PXENV_EXIT_SUCCESS ) {
1427                 DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
1428         }
1429         DBG ( "]" );
1430
1431         return ret;
1432 }
1433
1434 #endif /* PXE_EXPORT */