Merge from Etherboot 5.4
[people/lynusvaz/gpxe.git] / src / core / main.c
1 /**************************************************************************
2 Etherboot -  Network Bootstrap Program
3
4 Literature dealing with the network protocols:
5         ARP - RFC826
6         RARP - RFC903
7         UDP - RFC768
8         BOOTP - RFC951, RFC2132 (vendor extensions)
9         DHCP - RFC2131, RFC2132 (options)
10         TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
11         RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
12         NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
13         IGMP - RFC1112
14
15 **************************************************************************/
16
17 /* #define MDEBUG */
18
19 #include "etherboot.h"
20 #include "dev.h"
21 #include "nic.h"
22 #include "disk.h"
23 #include "timer.h"
24 #include "cpu.h"
25 #include "console.h"
26 #include "init.h"
27 #include "image.h"
28 #include <stdarg.h>
29
30 #ifdef CONFIG_FILO
31 #include <lib.h>
32 #endif
33
34 /* Linker symbols */
35 extern char _bss[], _ebss[];
36
37 jmp_buf restart_etherboot;
38 int     url_port;               
39
40 char as_main_program = 1;
41
42 #if 0
43
44 static inline unsigned long ask_boot(unsigned *index)
45 {
46         unsigned long order = DEFAULT_BOOT_ORDER;
47         *index = DEFAULT_BOOT_INDEX;
48 #ifdef LINUXBIOS
49         order = get_boot_order(order, index);
50 #endif
51 #if defined(ASK_BOOT)
52 #if ASK_BOOT >= 0
53         while(1) {
54                 int c = 0;
55                 printf(ASK_PROMPT);
56 #if ASK_BOOT > 0
57                 {
58                         unsigned long time;
59                         for ( time = currticks() + ASK_BOOT*TICKS_PER_SEC;
60                               !c && !iskey(); ) {
61                                 if (currticks() > time) c = ANS_DEFAULT;
62                         }
63                 }
64 #endif /* ASK_BOOT > 0 */
65                 if ( !c ) c = getchar();
66                 if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
67                 if ((c >= ' ') && (c <= '~')) putchar(c);
68                 putchar('\n');
69
70                 switch(c) {
71                 default:
72                         /* Nothing useful try again */
73                         continue;
74                 case ANS_QUIT:
75                         order = BOOT_NOTHING;
76                         *index = 0;
77                         break;
78                 case ANS_DEFAULT:
79                         /* Preserve the default boot order */
80                         break;
81                 case ANS_NETWORK:
82                         order = (BOOT_NIC     << (0*BOOT_BITS)) | 
83                                 (BOOT_NOTHING << (1*BOOT_BITS));
84                         *index = 0;
85                         break;
86                 case ANS_DISK:
87                         order = (BOOT_DISK    << (0*BOOT_BITS)) | 
88                                 (BOOT_NOTHING << (1*BOOT_BITS));
89                         *index = 0;
90                         break;
91                 case ANS_FLOPPY:
92                         order = (BOOT_FLOPPY  << (0*BOOT_BITS)) | 
93                                 (BOOT_NOTHING << (1*BOOT_BITS));
94                         *index = 0;
95                         break;
96                 }
97                 break;
98         }
99         putchar('\n');
100 #endif /* ASK_BOOT >= 0 */
101 #endif /* defined(ASK_BOOT) */
102         return order;
103 }
104
105 static inline void try_floppy_first(void)
106 {
107 #if (TRY_FLOPPY_FIRST > 0)
108         int i;
109         printf("Trying floppy");
110         disk_init();
111         for (i = TRY_FLOPPY_FIRST; i-- > 0; ) {
112                 putchar('.');
113                 if (pcbios_disk_read(0, 0, 0, 0, ((char *)FLOPPY_BOOT_LOCATION)) != 0x8000) {
114                         printf("using floppy\n");
115                         exit(0);
116                 }
117         }
118         printf("no floppy\n");
119 #endif /* TRY_FLOPPY_FIRST */   
120 }
121
122 static struct class_operations {
123         struct dev *dev;
124         int (*probe)(struct dev *dev);
125         int (*load_configuration)(struct dev *dev);
126         int (*load)(struct dev *dev);
127 }
128 operations[] = {
129         { &nic.dev,  eth_probe,  eth_load_configuration,  eth_load  },
130         { &disk.dev, disk_probe, disk_load_configuration, disk_load },
131         { &disk.dev, disk_probe, disk_load_configuration, disk_load },
132 };
133
134 #endif
135
136
137
138 static int main_loop(int state);
139 static int exit_ok;
140 static int exit_status;
141 static int initialized;
142
143
144 /**************************************************************************
145  * initialise() - perform any C-level initialisation
146  *
147  * This does not include initialising the NIC, but it does include
148  * e.g. getting the memory map, relocating to high memory,
149  * initialising the console, etc.
150  **************************************************************************
151  */
152 void initialise ( void ) {
153         /* Zero the BSS */
154         memset ( _bss, 0, _ebss - _bss );
155
156         /* Call all registered initialisation functions */
157         call_init_fns ();
158 }
159
160 /**************************************************************************
161 MAIN - Kick off routine
162 **************************************************************************/
163 int main ( void ) {
164         struct image *image;
165         void *image_context;
166         int skip = 0;
167
168         /* Print out configuration */
169         print_config();
170
171         /*
172          * Trivial main loop: we need to think about how we want to
173          * prompt the user etc.
174          *
175          */
176         for ( ; ; disable ( &dev ), call_reset_fns() ) {
177
178                 /* Get next boot device */
179                 if ( ! find_any_with_driver ( &dev, skip ) ) {
180                         /* Reached end of device list */
181                         printf ( "No more boot devices\n" );
182                         skip = 0;
183                         sleep ( 2 );
184                         continue;
185                 }
186
187                 /* Skip this device the next time we encounter it */
188                 skip = 1;
189
190                 /* Print out device information */
191                 printf ( "%s (%s) %s at %s\n",
192                          dev.bus_driver->name_device ( &dev.bus_dev ),
193                          dev.device_driver->name,
194                          dev.type_driver->name,
195                          dev.bus_driver->describe_device ( &dev.bus_dev ) );
196
197                 /* Probe boot device */
198                 if ( ! probe ( &dev ) ) {
199                         /* Device found on bus, but probe failed */
200                         printf ( "...probe failed: %m\n" );
201                         continue;
202                 }
203
204                 /* Print out device information */
205                 printf ( "%s %s has %s\n",
206                          dev.bus_driver->name_device ( &dev.bus_dev ),
207                          dev.type_driver->name,
208                          dev.type_driver->describe_device ( dev.type_dev ) );
209
210                 /* Configure boot device */
211                 if ( ! configure ( &dev ) ) {
212                         /* Configuration (e.g. DHCP) failed */
213                         printf ( "...configuration failed: %m\n" );
214                         continue;
215                 }
216
217                 /* Load boot file from the device */
218                 if ( ! autoload ( &dev, &image, &image_context ) ) {
219                         /* Load (e.g. TFTP) failed */
220                         printf ( "...load failed: %m\n" );
221                         continue;
222                 }
223
224                 /* Print out image information */
225                 printf ( "\nLoaded %s image\n", image->name );
226
227                 /* Disable devices? */
228                 cleanup();
229                 /* arch_on_exit(0); */
230
231                 /* Boot the image */
232                 if ( ! image->boot ( image_context ) ) {
233                         /* Boot failed */
234                         printf ( "...boot failed: %m\n" );
235                         continue;
236                 }
237                 
238                 /* Image returned */
239                 printf ( "...image returned\n" );
240         }
241
242         /* Call registered per-object exit functions */
243         call_exit_fns ();
244
245         return exit_status;
246 }
247
248 void exit(int status)
249 {
250         while(!exit_ok)
251                 ;
252         exit_status = status;
253         longjmp(restart_etherboot, 255);
254 }
255
256
257 #if 0
258
259 static int main_loop(int state)
260 {
261         /* Splitting main into 2 pieces makes the semantics of 
262          * which variables are preserved across a longjmp clean
263          * and predictable.
264          */
265         static unsigned long order;
266         static unsigned boot_index;
267         static struct dev * dev = 0;
268         static struct class_operations *ops;
269         static int type;
270         static int i;
271
272         if (!initialized) {
273                 initialized = 1;
274                 if (dev && (state >= 1) && (state <= 2)) {
275                         dev->how_probe = PROBE_AWAKE;
276                         dev->how_probe = ops->probe(dev);
277                         if (dev->how_probe == PROBE_FAILED) {
278                                 state = -1;
279                         }
280                         if (state == 1) {
281                                 /* The bootp reply might have been changed, re-parse.  */
282                                 decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
283 #ifdef  NO_DHCP_SUPPORT
284                                                BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 
285 #else
286                                                DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 
287 #endif  /* NO_DHCP_SUPPORT */
288                                                1);
289                         }
290                 }
291         }
292         switch(state) {
293         case 0:
294         {
295                 static int firsttime = 1;
296                 /* First time through */
297                 if (firsttime) {
298                         cleanup();
299                         firsttime = 0;
300                 } 
301 #ifdef  EXIT_IF_NO_OFFER
302                 else {
303                         cleanup();
304                         exit(0);
305                 }
306 #endif
307                 i = -1;
308                 state = 4;
309                 dev = 0;
310
311                 /* We just called setjmp ... */
312                 order = ask_boot(&boot_index);
313                 try_floppy_first();
314                 break;
315         }
316         case 4:
317                 cleanup();
318                 call_reset_fns();
319                 /* Find a dev entry to probe with */
320                 if (!dev) {
321                         int boot;
322                         int failsafe;
323
324                         /* Advance to the next device type */
325                         i++;
326                         boot = (order >> (i * BOOT_BITS)) & BOOT_MASK;
327                         type = boot & BOOT_TYPE_MASK;
328                         failsafe = (boot & BOOT_FAILSAFE) != 0;
329                         if (i >= MAX_BOOT_ENTRIES) {
330                                 type = BOOT_NOTHING;
331                         }
332                         if ((i == 0) && (type == BOOT_NOTHING)) {
333                                 /* Return to caller */
334                                 exit(0);
335                         }
336                         if (type >= BOOT_NOTHING) {
337                                 interruptible_sleep(2);
338                                 state = 0;
339                                 break;
340                         }
341                         ops = &operations[type];
342                         dev = ops->dev;
343                         dev->how_probe = PROBE_FIRST;
344                         dev->type = type;
345                         dev->failsafe = failsafe;
346                         dev->type_index = 0;
347                 } else {
348                         /* Advance to the next device of the same type */
349                         dev->how_probe = PROBE_NEXT;
350                 }
351                 state = 3;
352                 break;
353         case 3:
354                 state = -1;
355                 /* Removed the following line because it was causing
356                  * heap.o to be dragged in unnecessarily.  It's also
357                  * slightly puzzling: by resetting heap_base, doesn't
358                  * this mean that we permanently leak memory?
359                  */
360                 /* heap_base = allot(0); */
361                 dev->how_probe = ops->probe(dev);
362                 if (dev->how_probe == PROBE_FAILED) {
363                         dev = 0;
364                         state = 4;
365                 } else if (boot_index && (i == 0) && (boot_index != (unsigned)dev->type_index)) {
366                         printf("Wrong index\n");
367                         state = 4;
368                 }
369                 else {
370                         state = 2;
371                 }
372                 break;
373         case 2:
374                 state = -1;
375                 if (ops->load_configuration(dev) >= 0) {
376                         state = 1;
377                 }
378                 break;
379         case 1:
380                 /* Any return from load is a failure */
381                 ops->load(dev);
382                 state = -1;
383                 break;
384         case 256:
385                 state = 0;
386                 break;
387         case -3:
388                 i = MAX_BOOT_ENTRIES;
389                 type = BOOT_NOTHING;
390                 /* fall through */
391         default:
392                 printf("<abort>\n");
393                 state = 4;
394                 /* At the end goto state 0 */
395                 if ((type >= BOOT_NOTHING) || (i >= MAX_BOOT_ENTRIES)) {
396                         state = 0;
397                 }
398                 break;
399         }
400         return state;
401 }
402
403
404 #endif
405
406
407 /**************************************************************************
408 LOADKERNEL - Try to load kernel image
409 **************************************************************************/
410 #if 0
411 /* To be split out into individual files */
412 static const struct proto protos[] = {
413         { "x-tftm", url_tftm },
414         { "x-slam", url_slam },
415         { "nfs", nfs },
416         { "file", url_file },
417         { "tftp", tftp },
418         { "http", http },
419 };
420 #endif
421
422
423 /**************************************************************************
424 CLEANUP - shut down networking and console so that the OS may be called 
425 **************************************************************************/
426 void cleanup(void)
427 {
428         /* Stop receiving packets */
429         disable ( &dev );
430         initialized = 0;
431 }
432
433 /*
434  * Local variables:
435  *  c-basic-offset: 8
436  * End:
437  */