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