ae67b34da4000725c4f0a28b1933de58343cb062
[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_probe(data, len) do {} while(0)
81 #define multiboot_boot(entry) do {} while(0)
82 #endif
83
84
85 #ifdef WINCE_IMAGE
86 #include "../arch/i386/core/wince_loader.c"
87 #endif
88
89 #ifdef AOUT_IMAGE
90 #include "../arch/i386/core/aout_loader.c"
91 #endif
92
93 #ifdef TAGGED_IMAGE
94 #include "../arch/i386/core/tagged_loader.c"
95 #endif
96
97 #if defined(ELF_IMAGE) || defined(ELF64_IMAGE)
98 #include "elf_loader.c"
99 #endif
100
101 #if defined(COFF_IMAGE) 
102 #include "../arch/e1/core/coff_loader.c"
103 #endif
104
105 #ifdef IMAGE_FREEBSD
106 #include "../arch/i386/core/freebsd_loader.c"
107 #endif
108
109 #ifdef PXE_IMAGE
110 #include "../arch/i386/core/pxe_loader.c"
111 #endif
112
113 #ifdef RAW_IMAGE
114 #include "../arch/armnommu/core/raw_loader.c"
115 #endif
116
117 static void done(int do_cleanup)
118 {
119 #ifdef  SIZEINDICATOR
120         printf("K ");
121 #endif
122         printf("done\n");
123         /* We may not want to do the cleanup: when booting a PXE
124          * image, for example, we need to leave the network card
125          * enabled, and it helps debugging if the serial console
126          * remains enabled.  The call the cleanup() will be triggered
127          * when the PXE stack is shut down.
128          */
129         if ( do_cleanup ) {
130                 cleanup();
131                 arch_on_exit(0);
132         }
133 }
134
135 static int prep_segment(unsigned long start, unsigned long mid, unsigned long end,
136         unsigned long istart __unused, unsigned long iend __unused)
137 {
138         unsigned fit, i;
139
140 #if LOAD_DEBUG
141         printf ( "\nAbout to prepare segment [%lX,%lX)\n", start, end );
142         sleep ( 3 );
143 #endif
144
145         if (mid > end) {
146                 printf("filesz > memsz\n");
147                 return 0;
148         }
149         if ((end > virt_to_phys(_text)) && 
150                 (start < virt_to_phys(_end))) {
151                 printf("segment [%lX, %lX) overlaps etherboot [%lX, %lX)\n",
152                         start, end,
153                         virt_to_phys(_text), virt_to_phys(_end)
154                         );
155                 return 0;
156         }
157         if ((end > heap_ptr) && (start < heap_bot)) {
158                 printf("segment [%lX, %lX) overlaps heap [%lX, %lX)\n",
159                         start, end,
160                         heap_ptr, heap_bot
161                         );
162                 return 0;
163         }
164         fit = 0;
165         for(i = 0; i < meminfo.map_count; i++) {
166                 unsigned long long r_start, r_end;
167                 if (meminfo.map[i].type != E820_RAM)
168                         continue;
169                 r_start = meminfo.map[i].addr;
170                 r_end = r_start + meminfo.map[i].size;
171                 if ((start >= r_start) && (end <= r_end)) {
172                         fit = 1;
173                         break;
174                 }
175         }
176         if (!fit) {
177                 printf("\nsegment [%lX,%lX) does not fit in any memory region\n",
178                         start, end);
179 #if LOAD_DEBUG
180                 printf("Memory regions(%d):\n", meminfo.map_count);
181                 for(i = 0; i < meminfo.map_count; i++) {
182                         unsigned long long r_start, r_end;
183                         if (meminfo.map[i].type != E820_RAM)
184                                 continue;
185                         r_start = meminfo.map[i].addr;
186                         r_end = r_start + meminfo.map[i].size;
187                         printf("[%X%X, %X%X) type %d\n", 
188                                 (unsigned long)(r_start >> 32),
189                                 (unsigned long)r_start,
190                                 (unsigned long)(r_end >> 32),
191                                 (unsigned long)r_end,
192                                 meminfo.map[i].type);
193                 }
194 #endif
195                 return 0;
196         }
197 #if LOAD_DEBUG
198         /* Zap the whole lot.  Do this so that if we're treading on
199          * anything, it shows up now, when the debug message is
200          * visible, rather than when we're partway through downloading
201          * the file.
202          *
203          * If you see an entire screen full of exclamation marks, then
204          * you've almost certainly written all over the display RAM.
205          * This is likely to happen if the status of the A20 line gets
206          * screwed up.  Of course, if this happens, it's a good bet
207          * that you've also trashed the whole of low memory, so expect
208          * interesting things to happen...
209          */
210         memset(phys_to_virt(start), '!', mid - start);
211 #endif
212         /* Zero the bss */
213         if (end > mid) {
214                 memset(phys_to_virt(mid), 0, end - mid);
215         }
216         return 1;
217 }
218
219 static unsigned long find_segment(unsigned long size, unsigned long align)
220 {
221         unsigned i;
222         /* Verify I have a power of 2 alignment */
223         if (align & (align - 1)) {
224                 return ULONG_MAX;
225         }
226         for(i = 0; i < meminfo.map_count; i++) {
227                 unsigned long r_start, r_end;
228                 if (meminfo.map[i].type != E820_RAM)
229                         continue;
230                 if ((meminfo.map[i].addr + meminfo.map[i].size) > ULONG_MAX) {
231                         continue;
232                 }
233                 r_start = meminfo.map[i].addr;
234                 r_end = r_start + meminfo.map[i].size;
235                 /* Don't allow the segment to overlap etherboot */
236                 if ((r_end > virt_to_phys(_text)) && (r_start < virt_to_phys(_text))) {
237                         r_end = virt_to_phys(_text);
238                 }
239                 if ((r_start > virt_to_phys(_text)) && (r_start < virt_to_phys(_end))) {
240                         r_start = virt_to_phys(_end);
241                 }
242                 /* Don't allow the segment to overlap the heap */
243                 if ((r_end > heap_ptr) && (r_start < heap_ptr)) {
244                         r_end = heap_ptr;
245                 }
246                 if ((r_start > heap_ptr) && (r_start < heap_bot)) {
247                         r_start = heap_ptr;
248                 }
249                 r_start = (r_start + align - 1) & ~(align - 1);
250                 if ((r_end >= r_start) && ((r_end - r_start) >= size)) {
251                         return r_start;
252                 }
253         }
254         /* I did not find anything :( */
255         return ULONG_MAX;
256 }
257
258 /**************************************************************************
259 PROBE_IMAGE - Detect image file type
260 **************************************************************************/
261 os_download_t probe_image(unsigned char *data, unsigned int len)
262 {
263         os_download_t os_download = 0;
264 #ifdef AOUT_IMAGE
265         if (!os_download) os_download = aout_probe(data, len);
266 #endif
267 #ifdef ELF_IMAGE
268         if (!os_download) os_download = elf32_probe(data, len);
269 #endif
270 #ifdef ELF64_IMAGE
271         if (!os_download) os_download = elf64_probe(data, len);
272 #endif
273 #ifdef COFF_IMAGE
274     if (!os_download) os_download = coff_probe(data, len);
275 #endif
276 #ifdef WINCE_IMAGE
277         if (!os_download) os_download = wince_probe(data, len);
278 #endif
279 #ifdef TAGGED_IMAGE
280         if (!os_download) os_download = tagged_probe(data, len);
281 #endif
282 /* PXE_IMAGE must always be last */
283 #ifdef PXE_IMAGE
284         if (!os_download) os_download = pxe_probe(data, len);
285 #endif
286 #ifdef RAW_IMAGE
287         if (!os_download) os_download = raw_probe(data, len);
288 #endif
289         return os_download;
290 }
291
292 /**************************************************************************
293 LOAD_BLOCK - Try to load file
294 **************************************************************************/
295 int load_block(unsigned char *data, unsigned int block, unsigned int len, int eof)
296 {
297         static os_download_t os_download;
298         static sector_t skip_sectors;
299         static unsigned int skip_bytes;
300 #ifdef  SIZEINDICATOR
301         static int rlen = 0;
302
303         if (block == 1)
304         {
305                 rlen=len;
306                 printf("XXXX");
307         }
308         if (!(block % 4) || eof) {
309                 int size;
310                 size = ((block-1) * rlen + len) / 1024;
311
312                 putchar('\b');
313                 putchar('\b');
314                 putchar('\b');
315                 putchar('\b');
316
317                 putchar('0' + (size/1000)%10);
318                 putchar('0' + (size/100)%10);
319                 putchar('0' + (size/10)%10);
320                 putchar('0' + (size/1)%10);
321         }
322 #endif
323         if (block == 1)
324         {
325                 skip_sectors = 0;
326                 skip_bytes = 0;
327                 os_download = probe_image(data, len);
328                 if (!os_download) {
329                         printf("error: not a valid image\n");
330 #if 0
331                         printf("block: %d len: %d\n", block, len);
332                         printf("%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n",
333                                 data[0], data[1], data[2], data[3],
334                                 data[4], data[5], data[6], data[7]);
335 #endif
336                         return 0;
337                 }
338         } /* end of block zero processing */
339
340         /* Either len is greater or the skip is greater */
341         if ((skip_sectors > (len >> 9)) ||
342                 ((skip_sectors == (len >> 9)) && (skip_bytes >= (len & 0x1ff)))) {
343                 /* If I don't have enough bytes borrow them from skip_sectors */
344                 if (skip_bytes < len) {
345                         skip_sectors -= (len - skip_bytes + 511) >> 9;
346                         skip_bytes += (len - skip_bytes + 511) & ~0x1ff;
347                 }
348                 skip_bytes -= len;
349         }
350         else {
351                 len -= (skip_sectors << 9) + skip_bytes;
352                 data += (skip_sectors << 9) + skip_bytes;
353         }
354         skip_sectors = os_download(data, len, eof);
355         skip_bytes = 0;
356         
357         return 1;
358 }
359
360 /*
361  * Local variables:
362  *  c-basic-offset: 8
363  * End:
364  */
365