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