5e92a8e0e7ad8d346e1c3dcc8c88af93f76526c1
[etherboot.git] / src / core / osloader.c
1 /**************************************************************************
2 OS loader
3
4 Author: Markus Gutschke (gutschk@math.uni-muenster.de)
5   Date: Sep/95
6 Modifications: Ken Yap (for Etherboot/16)
7   Doug Ambrisko (ELF and a.out support)
8   Klaus Espenlaub (rewrote ELF and a.out (did it really work before?) support,
9       added ELF Multiboot images).  Someone should merge the ELF and a.out
10       loaders, as most of the code is now identical.  Maybe even NBI could be
11       rewritten and merged into the generic loading framework.  This should
12       save quite a few bytes of code if you have selected more than one format.
13   Ken Yap (Jan 2001)
14       Added support for linear entry addresses in tagged images,
15       which allows a more efficient protected mode call instead of
16       going to real mode and back. Also means entry addresses > 1 MB can
17       be called.  Conditional on the LINEAR_EXEC_ADDR bit.
18       Added support for Etherboot extension calls. Conditional on the
19       TAGGED_PROGRAM_RETURNS bit. Implies LINEAR_EXEC_ADDR.
20       Added support for non-MULTIBOOT ELF which also supports Etherboot
21       extension calls. Conditional on the ELF_PROGRAM_RETURNS bit.
22
23 **************************************************************************/
24
25 /*
26  * This program is free software; you can redistribute it and/or
27  * modify it under the terms of the GNU General Public License as
28  * published by the Free Software Foundation; either version 2, or (at
29  * your option) any later version.
30  */
31
32 #include "etherboot.h"
33
34 struct os_entry_regs os_regs;
35
36 static struct ebinfo            loaderinfo = {
37         VERSION_MAJOR, VERSION_MINOR,
38         0
39 };
40
41 #define LOAD_DEBUG 0
42
43 static int prep_segment(unsigned long start, unsigned long mid, unsigned long end,
44         unsigned long istart, unsigned long iend);
45 static unsigned long find_segment(unsigned long size, unsigned long align);
46 static sector_t dead_download ( unsigned char *data, unsigned int len, int eof);
47 static void done(int do_cleanup);
48
49 #if defined(IMAGE_FREEBSD) && defined(ELF_IMAGE)
50 static void elf_freebsd_probe(void);
51 static void elf_freebsd_fixup_segment(void);
52 static void elf_freebsd_find_segment_end(void);
53 static int elf_freebsd_debug_loader(unsigned int offset);
54 static void elf_freebsd_boot(unsigned long entry);
55 #else
56 #define elf_freebsd_probe() do {} while(0)
57 #define elf_freebsd_fixup_segment()  do {} while(0)
58 #define elf_freebsd_find_segment_end() do {} while(0)
59 #define elf_freebsd_debug_loader(off) (0)
60 #define elf_freebsd_boot(entry) do {} while(0)
61 #endif
62 #if defined(IMAGE_FREEBSD) && defined(AOUT_IMAGE)
63 static void aout_freebsd_probe(void);
64 static void aout_freebsd_boot(void);
65 #else
66 #define aout_freebsd_probe() do {} while(0)
67 #define aout_freebsd_boot() do {} while(0)
68 #endif
69
70 /**************************************************************************
71 dead_download - Restart etherboot if probe image fails
72 **************************************************************************/
73 static sector_t dead_download ( unsigned char *data __unused, unsigned int len __unused, int eof __unused) {
74         longjmp(restart_etherboot, -2);
75 }
76
77 #ifdef  IMAGE_MULTIBOOT
78 #include "../arch/i386/core/multiboot_loader.c"
79 #else
80 #define multiboot_init() do {} while(0)
81 #define multiboot_peek(data, len) do {} while(0)
82 #define multiboot_boot(entry) do {} while(0)
83 #endif
84
85
86 #ifdef WINCE_IMAGE
87 #include "../arch/i386/core/wince_loader.c"
88 #endif
89
90 #ifdef AOUT_IMAGE
91 #include "../arch/i386/core/aout_loader.c"
92 #endif
93
94 #ifdef TAGGED_IMAGE
95 #include "../arch/i386/core/tagged_loader.c"
96 #endif
97
98 #if defined(ELF_IMAGE) || defined(ELF64_IMAGE)
99 #include "elf_loader.c"
100 #endif
101
102 #if defined(COFF_IMAGE) 
103 #include "../arch/e1/core/coff_loader.c"
104 #endif
105
106 #ifdef IMAGE_FREEBSD
107 #include "../arch/i386/core/freebsd_loader.c"
108 #endif
109
110 #ifdef PXE_IMAGE
111 #include "../arch/i386/core/pxe_loader.c"
112 #endif
113
114 #ifdef RAW_IMAGE
115 #include "../arch/armnommu/core/raw_loader.c"
116 #endif
117
118 static void done(int do_cleanup)
119 {
120 #ifdef  SIZEINDICATOR
121         printf("K ");
122 #endif
123         printf("done\n");
124         /* We may not want to do the cleanup: when booting a PXE
125          * image, for example, we need to leave the network card
126          * enabled, and it helps debugging if the serial console
127          * remains enabled.  The call the cleanup() will be triggered
128          * when the PXE stack is shut down.
129          */
130         if ( do_cleanup ) {
131                 cleanup();
132                 arch_on_exit(0);
133         }
134 }
135
136 static int prep_segment(unsigned long start, unsigned long mid, unsigned long end,
137         unsigned long istart __unused, unsigned long iend __unused)
138 {
139         unsigned fit, i;
140
141 #if LOAD_DEBUG
142         printf ( "\nAbout to prepare segment [%lX,%lX)\n", start, end );
143         sleep ( 3 );
144 #endif
145
146         if (mid > end) {
147                 printf("filesz > memsz\n");
148                 return 0;
149         }
150         if ((end > virt_to_phys(_text)) && 
151                 (start < virt_to_phys(_end))) {
152                 printf("segment [%lX, %lX) overlaps etherboot [%lX, %lX)\n",
153                         start, end,
154                         virt_to_phys(_text), virt_to_phys(_end)
155                         );
156                 return 0;
157         }
158         if ((end > heap_ptr) && (start < heap_bot)) {
159                 printf("segment [%lX, %lX) overlaps heap [%lX, %lX)\n",
160                         start, end,
161                         heap_ptr, heap_bot
162                         );
163                 return 0;
164         }
165         fit = 0;
166         for(i = 0; i < meminfo.map_count; i++) {
167                 unsigned long long r_start, r_end;
168                 if (meminfo.map[i].type != E820_RAM)
169                         continue;
170                 r_start = meminfo.map[i].addr;
171                 r_end = r_start + meminfo.map[i].size;
172                 if ((start >= r_start) && (end <= r_end)) {
173                         fit = 1;
174                         break;
175                 }
176         }
177         if (!fit) {
178                 printf("\nsegment [%lX,%lX) does not fit in any memory region\n",
179                         start, end);
180 #if LOAD_DEBUG
181                 printf("Memory regions(%d):\n", meminfo.map_count);
182                 for(i = 0; i < meminfo.map_count; i++) {
183                         unsigned long long r_start, r_end;
184                         if (meminfo.map[i].type != E820_RAM)
185                                 continue;
186                         r_start = meminfo.map[i].addr;
187                         r_end = r_start + meminfo.map[i].size;
188                         printf("[%X%X, %X%X) type %d\n", 
189                                 (unsigned long)(r_start >> 32),
190                                 (unsigned long)r_start,
191                                 (unsigned long)(r_end >> 32),
192                                 (unsigned long)r_end,
193                                 meminfo.map[i].type);
194                 }
195 #endif
196                 return 0;
197         }
198 #if LOAD_DEBUG
199         /* Zap the whole lot.  Do this so that if we're treading on
200          * anything, it shows up now, when the debug message is
201          * visible, rather than when we're partway through downloading
202          * the file.
203          *
204          * If you see an entire screen full of exclamation marks, then
205          * you've almost certainly written all over the display RAM.
206          * This is likely to happen if the status of the A20 line gets
207          * screwed up.  Of course, if this happens, it's a good bet
208          * that you've also trashed the whole of low memory, so expect
209          * interesting things to happen...
210          */
211         memset(phys_to_virt(start), '!', mid - start);
212 #endif
213         /* Zero the bss */
214         if (end > mid) {
215                 memset(phys_to_virt(mid), 0, end - mid);
216         }
217         return 1;
218 }
219
220 static unsigned long find_segment(unsigned long size, unsigned long align)
221 {
222         unsigned i;
223         /* Verify I have a power of 2 alignment */
224         if (align & (align - 1)) {
225                 return ULONG_MAX;
226         }
227         for(i = 0; i < meminfo.map_count; i++) {
228                 unsigned long r_start, r_end;
229                 if (meminfo.map[i].type != E820_RAM)
230                         continue;
231                 if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
232                         continue;
233                 }
234                 r_start = meminfo.map[i].addr;
235                 r_end = r_start + meminfo.map[i].size;
236                 /* Don't allow the segment to overlap etherboot */
237                 if ((r_end > virt_to_phys(_text)) && (r_start < virt_to_phys(_text))) {
238                         r_end = virt_to_phys(_text);
239                 }
240                 if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
241                         r_start = virt_to_phys(_end);
242                 }
243                 /* Don't allow the segment to overlap the heap */
244                 if ((r_end > heap_ptr) && (r_start < heap_ptr)) {
245                         r_end = heap_ptr;
246                 }
247                 if ((r_start > heap_ptr) && (r_start < heap_bot)) {
248                         r_start = heap_ptr;
249                 }
250                 r_start = (r_start + align - 1) & ~(align - 1);
251                 if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
252                         return r_start;
253                 }
254         }
255         /* I did not find anything :( */
256         return ULONG_MAX;
257 }
258
259 /**************************************************************************
260 PROBE_IMAGE - Detect image file type
261 **************************************************************************/
262 os_download_t probe_image(unsigned char *data, unsigned int len)
263 {
264         os_download_t os_download = 0;
265 #ifdef AOUT_IMAGE
266         if (!os_download) os_download = aout_probe(data, len);
267 #endif
268 #ifdef ELF_IMAGE
269         if (!os_download) os_download = elf32_probe(data, len);
270 #endif
271 #ifdef ELF64_IMAGE
272         if (!os_download) os_download = elf64_probe(data, len);
273 #endif
274 #ifdef COFF_IMAGE
275     if (!os_download) os_download = coff_probe(data, len);
276 #endif
277 #ifdef WINCE_IMAGE
278         if (!os_download) os_download = wince_probe(data, len);
279 #endif
280 #ifdef TAGGED_IMAGE
281         if (!os_download) os_download = tagged_probe(data, len);
282 #endif
283 /* PXE_IMAGE must always be last */
284 #ifdef PXE_IMAGE
285         if (!os_download) os_download = pxe_probe(data, len);
286 #endif
287 #ifdef RAW_IMAGE
288         if (!os_download) os_download = raw_probe(data, len);
289 #endif
290         return os_download;
291 }
292
293 /**************************************************************************
294 LOAD_BLOCK - Try to load file
295 **************************************************************************/
296 int load_block(unsigned char *data, unsigned int block, unsigned int len, int eof)
297 {
298         static os_download_t os_download;
299         static sector_t skip_sectors;
300         static unsigned int skip_bytes;
301 #ifdef  SIZEINDICATOR
302         static int rlen = 0;
303
304         if (block == 1)
305         {
306                 rlen=len;
307                 printf("XXXX");
308         }
309         if (!(block % 4) || eof) {
310                 int size;
311                 size = ((block-1) * rlen + len) / 1024;
312
313                 putchar('\b');
314                 putchar('\b');
315                 putchar('\b');
316                 putchar('\b');
317
318                 putchar('0' + (size/1000)%10);
319                 putchar('0' + (size/100)%10);
320                 putchar('0' + (size/10)%10);
321                 putchar('0' + (size/1)%10);
322         }
323 #endif
324         if (block == 1)
325         {
326                 skip_sectors = 0;
327                 skip_bytes = 0;
328                 os_download = probe_image(data, len);
329                 if (!os_download) {
330                         printf("error: not a valid image\n");
331 #if 0
332                         printf("block: %d len: %d\n", block, len);
333                         printf("%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
334                                 data[0], data[1], data[2], data[3],
335                                 data[4], data[5], data[6], data[7]);
336 #endif
337                         return 0;
338                 }
339         } /* end of block zero processing */
340
341 #if defined(ELF_IMAGE) && defined(IMAGE_MULTIBOOT)
342         if (os_download == elf32_download) {
343                 multiboot_peek(data, len);
344         }
345 #endif /* defined(ELF_IMAGE) && defined(IMAGE_MULTIBOOT) */
346
347         /* Either len is greater or the skip is greater */
348         if ((skip_sectors > (len >> 9)) ||
349                 ((skip_sectors == (len >> 9)) && (skip_bytes >= (len & 0x1ff)))) {
350                 /* If I don't have enough bytes borrow them from skip_sectors */
351                 if (skip_bytes < len) {
352                         skip_sectors -= (len - skip_bytes + 511) >> 9;
353                         skip_bytes += (len - skip_bytes + 511) & ~0x1ff;
354                 }
355                 skip_bytes -= len;
356         }
357         else {
358                 len -= (skip_sectors << 9) + skip_bytes;
359                 data += (skip_sectors << 9) + skip_bytes;
360                 skip_sectors = os_download(data, len, eof);
361                 skip_bytes = 0;
362         }
363         
364         return 1;
365 }
366
367 /*
368  * Local variables:
369  *  c-basic-offset: 8
370  * End:
371  */
372