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