bd1bad35ea57588f027c41a16eb3a1df8bc54593
[people/xl0/gpxe.git] / src / arch / i386 / image / pxe_image.c
1 /*
2  * PXE image loader for Etherboot.
3  * 
4  * Note: There is no signature check for PXE images because there is
5  * no signature.  Well done, Intel!  Consequently, pxe_probe() must be
6  * called last of all the image_probe() routines, because it will
7  * *always* claim the image.
8  */
9
10 #ifndef PXE_EXPORT
11 #error PXE_IMAGE requires PXE_EXPORT
12 #endif
13
14 #include "etherboot.h"
15 #include "pxe_callbacks.h"
16 #include "pxe.h"
17
18 unsigned long pxe_load_offset;
19
20 static sector_t pxe_download ( unsigned char *data,
21                                unsigned int len, int eof );
22
23 static inline os_download_t pxe_probe ( unsigned char *data __unused,
24                                         unsigned int len __unused ) {
25         printf("(PXE)");
26         pxe_load_offset = 0;
27         return pxe_download;
28 }
29
30 static sector_t pxe_download ( unsigned char *data,
31                                unsigned int len, int eof ) {
32         unsigned long block_address = PXE_LOAD_ADDRESS + pxe_load_offset;
33         PXENV_STATUS_t nbp_exit;
34
35         /* Check segment will fit.  We can't do this in probe()
36          * because there's nothing in the non-existent header to tell
37          * us how long the image is.
38          */
39         if ( ! prep_segment ( block_address, block_address + len, 
40                               block_address + len,
41                               pxe_load_offset, pxe_load_offset + len ) ) {
42                 longjmp ( restart_etherboot, -2 );
43         }
44
45         /* Load block into memory, continue loading until eof */
46         memcpy ( phys_to_virt ( block_address ), data, len );
47         pxe_load_offset += len;
48         if ( ! eof ) { 
49                 return 0;
50         }
51
52         /* Start up PXE NBP */
53         done ( 0 );
54
55         /* Install and activate a PXE stack */
56         pxe_stack = install_pxe_stack ( NULL );
57         if ( ensure_pxe_state ( READY ) ) {
58                 /* Invoke the NBP */
59                 nbp_exit = xstartpxe();
60         } else {
61                 /* Fake success so we tear down the stack */
62                 nbp_exit = PXENV_STATUS_SUCCESS;
63         }
64
65         /* NBP has three exit codes:
66          *   PXENV_STATUS_KEEP_UNDI : keep UNDI and boot next device
67          *   PXENV_STATUS_KEEP_ALL  : keep all and boot next device
68          *   anything else : remove all and boot next device
69          * 
70          * Strictly, we're meant to hand back to the BIOS, but this
71          * would prevent the useful combination of "PXE NBP fails, so
72          * let Etherboot try to boot its next device".  We therefore
73          * take liberties.
74          */
75         if ( nbp_exit != PXENV_STATUS_KEEP_UNDI &&
76              nbp_exit != PXENV_STATUS_KEEP_ALL ) {
77                 /* Tear down PXE stack */
78                 remove_pxe_stack();
79         }
80
81         /* Boot next device.  Under strict PXE compliance, exit back
82          * to the BIOS, otherwise let Etherboot move to the next
83          * device.
84          */
85 #ifdef PXE_STRICT
86         longjmp ( restart_etherboot, 255 );
87 #else
88         longjmp ( restart_etherboot, 4 );
89 #endif
90         
91         /* Never reached; avoid compiler warning */
92         return ( 0 );
93 }