191ba841883a66c8b6ccd0451238865452f884d9
[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 "cmdline.h"
26 #include "console.h"
27 #include <gpxe/init.h>
28 #include "image.h"
29 #include <stdarg.h>
30
31 #include <gpxe/device.h>
32 #include <gpxe/heap.h>
33 #include <gpxe/netdevice.h>
34 #include <gpxe/shell.h>
35 #include <gpxe/shell_banner.h>
36
37 /* Linker symbols */
38 extern char _bss[], _ebss[];
39
40 jmp_buf restart_etherboot;
41 int     url_port;               
42
43 char as_main_program = 1;
44
45 #if 0
46
47 static inline unsigned long ask_boot(unsigned *index)
48 {
49         unsigned long order = DEFAULT_BOOT_ORDER;
50         *index = DEFAULT_BOOT_INDEX;
51 #ifdef LINUXBIOS
52         order = get_boot_order(order, index);
53 #endif
54 #if defined(ASK_BOOT)
55 #if ASK_BOOT >= 0
56         while(1) {
57                 int c = 0;
58                 printf(ASK_PROMPT);
59 #if ASK_BOOT > 0
60                 {
61                         unsigned long time;
62                         for ( time = currticks() + ASK_BOOT*TICKS_PER_SEC;
63                               !c && !iskey(); ) {
64                                 if (currticks() > time) c = ANS_DEFAULT;
65                         }
66                 }
67 #endif /* ASK_BOOT > 0 */
68                 if ( !c ) c = getchar();
69                 if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
70                 if ((c >= ' ') && (c <= '~')) putchar(c);
71                 putchar('\n');
72
73                 switch(c) {
74                 default:
75                         /* Nothing useful try again */
76                         continue;
77                 case ANS_QUIT:
78                         order = BOOT_NOTHING;
79                         *index = 0;
80                         break;
81                 case ANS_DEFAULT:
82                         /* Preserve the default boot order */
83                         break;
84                 case ANS_NETWORK:
85                         order = (BOOT_NIC     << (0*BOOT_BITS)) | 
86                                 (BOOT_NOTHING << (1*BOOT_BITS));
87                         *index = 0;
88                         break;
89                 case ANS_DISK:
90                         order = (BOOT_DISK    << (0*BOOT_BITS)) | 
91                                 (BOOT_NOTHING << (1*BOOT_BITS));
92                         *index = 0;
93                         break;
94                 case ANS_FLOPPY:
95                         order = (BOOT_FLOPPY  << (0*BOOT_BITS)) | 
96                                 (BOOT_NOTHING << (1*BOOT_BITS));
97                         *index = 0;
98                         break;
99                 }
100                 break;
101         }
102         putchar('\n');
103 #endif /* ASK_BOOT >= 0 */
104 #endif /* defined(ASK_BOOT) */
105         return order;
106 }
107
108 static inline void try_floppy_first(void)
109 {
110 #if (TRY_FLOPPY_FIRST > 0)
111         int i;
112         printf("Trying floppy");
113         disk_init();
114         for (i = TRY_FLOPPY_FIRST; i-- > 0; ) {
115                 putchar('.');
116                 if (pcbios_disk_read(0, 0, 0, 0, ((char *)FLOPPY_BOOT_LOCATION)) != 0x8000) {
117                         printf("using floppy\n");
118                         exit(0);
119                 }
120         }
121         printf("no floppy\n");
122 #endif /* TRY_FLOPPY_FIRST */   
123 }
124
125 static struct class_operations {
126         struct dev *dev;
127         int (*probe)(struct dev *dev);
128         int (*load_configuration)(struct dev *dev);
129         int (*load)(struct dev *dev);
130 }
131 operations[] = {
132         { &nic.dev,  eth_probe,  eth_load_configuration,  eth_load  },
133         { &disk.dev, disk_probe, disk_load_configuration, disk_load },
134         { &disk.dev, disk_probe, disk_load_configuration, disk_load },
135 };
136
137 #endif
138
139 #if 0
140 static int main_loop(int state);
141 static int exit_ok;
142 static int initialized;
143 #endif
144
145 static int exit_status;
146
147 void test_dhcp ( struct net_device *netdev );
148
149 /**************************************************************************
150 MAIN - Kick off routine
151 **************************************************************************/
152 int main ( void ) {
153         struct net_device *netdev;
154
155         /* Call all registered initialisation functions */
156         init_heap();
157         call_init_fns ();
158         probe_devices();
159
160         if ( shell_banner() ) {
161                 shell();
162         }
163
164         netdev = next_netdev ();
165         if ( netdev ) {
166                 test_dhcp ( netdev );
167         } else {
168                 printf ( "No network device found\n" );
169         }
170
171         printf ( "Press any key to exit\n" );
172         getchar();
173
174         remove_devices();
175         call_exit_fns ();
176
177         return exit_status;
178 }
179
180 #if 0
181
182 void exit(int status)
183 {
184         while(!exit_ok)
185                 ;
186         exit_status = status;
187         longjmp(restart_etherboot, 255);
188 }
189
190
191
192 static int main_loop(int state)
193 {
194         /* Splitting main into 2 pieces makes the semantics of 
195          * which variables are preserved across a longjmp clean
196          * and predictable.
197          */
198         static unsigned long order;
199         static unsigned boot_index;
200         static struct dev * dev = 0;
201         static struct class_operations *ops;
202         static int type;
203         static int i;
204
205         if (!initialized) {
206                 initialized = 1;
207                 if (dev && (state >= 1) && (state <= 2)) {
208                         dev->how_probe = PROBE_AWAKE;
209                         dev->how_probe = ops->probe(dev);
210                         if (dev->how_probe == PROBE_FAILED) {
211                                 state = -1;
212                         }
213                         if (state == 1) {
214                                 /* The bootp reply might have been changed, re-parse.  */
215                                 decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
216 #ifdef  NO_DHCP_SUPPORT
217                                                BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 
218 #else
219                                                DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 
220 #endif  /* NO_DHCP_SUPPORT */
221                                                1);
222                         }
223                 }
224         }
225         switch(state) {
226         case 0:
227         {
228                 static int firsttime = 1;
229                 /* First time through */
230                 if (firsttime) {
231                         cleanup();
232                         firsttime = 0;
233                 } 
234 #ifdef  EXIT_IF_NO_OFFER
235                 else {
236                         cleanup();
237                         exit(0);
238                 }
239 #endif
240                 i = -1;
241                 state = 4;
242                 dev = 0;
243
244                 /* We just called setjmp ... */
245                 order = ask_boot(&boot_index);
246                 try_floppy_first();
247                 break;
248         }
249         case 4:
250                 cleanup();
251                 call_reset_fns();
252                 /* Find a dev entry to probe with */
253                 if (!dev) {
254                         int boot;
255                         int failsafe;
256
257                         /* Advance to the next device type */
258                         i++;
259                         boot = (order >> (i * BOOT_BITS)) & BOOT_MASK;
260                         type = boot & BOOT_TYPE_MASK;
261                         failsafe = (boot & BOOT_FAILSAFE) != 0;
262                         if (i >= MAX_BOOT_ENTRIES) {
263                                 type = BOOT_NOTHING;
264                         }
265                         if ((i == 0) && (type == BOOT_NOTHING)) {
266                                 /* Return to caller */
267                                 exit(0);
268                         }
269                         if (type >= BOOT_NOTHING) {
270                                 interruptible_sleep(2);
271                                 state = 0;
272                                 break;
273                         }
274                         ops = &operations[type];
275                         dev = ops->dev;
276                         dev->how_probe = PROBE_FIRST;
277                         dev->type = type;
278                         dev->failsafe = failsafe;
279                         dev->type_index = 0;
280                 } else {
281                         /* Advance to the next device of the same type */
282                         dev->how_probe = PROBE_NEXT;
283                 }
284                 state = 3;
285                 break;
286         case 3:
287                 state = -1;
288                 /* Removed the following line because it was causing
289                  * heap.o to be dragged in unnecessarily.  It's also
290                  * slightly puzzling: by resetting heap_base, doesn't
291                  * this mean that we permanently leak memory?
292                  */
293                 /* heap_base = allot(0); */
294                 dev->how_probe = ops->probe(dev);
295                 if (dev->how_probe == PROBE_FAILED) {
296                         dev = 0;
297                         state = 4;
298                 } else if (boot_index && (i == 0) && (boot_index != (unsigned)dev->type_index)) {
299                         printf("Wrong index\n");
300                         state = 4;
301                 }
302                 else {
303                         state = 2;
304                 }
305                 break;
306         case 2:
307                 state = -1;
308                 if (ops->load_configuration(dev) >= 0) {
309                         state = 1;
310                 }
311                 break;
312         case 1:
313                 /* Any return from load is a failure */
314                 ops->load(dev);
315                 state = -1;
316                 break;
317         case 256:
318                 state = 0;
319                 break;
320         case -3:
321                 i = MAX_BOOT_ENTRIES;
322                 type = BOOT_NOTHING;
323                 /* fall through */
324         default:
325                 printf("<abort>\n");
326                 state = 4;
327                 /* At the end goto state 0 */
328                 if ((type >= BOOT_NOTHING) || (i >= MAX_BOOT_ENTRIES)) {
329                         state = 0;
330                 }
331                 break;
332         }
333         return state;
334 }
335
336
337 #endif
338
339
340 /**************************************************************************
341 LOADKERNEL - Try to load kernel image
342 **************************************************************************/
343 #if 0
344 /* To be split out into individual files */
345 static const struct proto protos[] = {
346         { "x-tftm", url_tftm },
347         { "x-slam", url_slam },
348         { "nfs", nfs },
349         { "file", url_file },
350         { "tftp", tftp },
351         { "http", http },
352 };
353 #endif
354
355 /**************************************************************************
356 CLEANUP - shut down networking and console so that the OS may be called 
357 **************************************************************************/
358 #if 0
359 void cleanup(void)
360 {
361         /* Stop receiving packets */
362         disable ( &dev );
363         initialized = 0;
364 }
365 #endif
366
367 /*
368  * Local variables:
369  *  c-basic-offset: 8
370  * End:
371  */