Initial code release
[external/syslinux.git] / gpxe / src / arch / i386 / core / freebsd_loader.c
1 /* bootinfo */
2 #define BOOTINFO_VERSION 1
3 #define NODEV           (-1)    /* non-existent device */
4 #define PAGE_SHIFT      12              /* LOG2(PAGE_SIZE) */
5 #define PAGE_SIZE       (1<<PAGE_SHIFT) /* bytes/page */
6 #define PAGE_MASK       (PAGE_SIZE-1)
7 #define N_BIOS_GEOM     8
8
9 struct bootinfo {
10         unsigned int            bi_version;
11         const unsigned char     *bi_kernelname;
12         struct nfs_diskless     *bi_nfs_diskless;
13                                 /* End of fields that are always present. */
14 #define bi_endcommon            bi_n_bios_used
15         unsigned int            bi_n_bios_used;
16         unsigned long           bi_bios_geom[N_BIOS_GEOM];
17         unsigned int            bi_size;
18         unsigned char           bi_memsizes_valid;
19         unsigned char           bi_pad[3];
20         unsigned long           bi_basemem;
21         unsigned long           bi_extmem;
22         unsigned long           bi_symtab;
23         unsigned long           bi_esymtab;
24         /* Note that these are in the FreeBSD headers but were not here... */
25         unsigned long           bi_kernend;             /* end of kernel space */
26         unsigned long           bi_envp;                /* environment */
27         unsigned long           bi_modulep;             /* preloaded modules */
28 };
29
30 static struct bootinfo bsdinfo;
31
32 #ifdef ELF_IMAGE
33 static Elf32_Shdr *shdr;        /* To support the FreeBSD kludge! */
34 static Address symtab_load;
35 static Address symstr_load;
36 static int symtabindex;
37 static int symstrindex;
38 #endif
39
40 static enum {
41         Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
42 } image_type = Unknown;
43
44 static unsigned int off;
45
46
47 #ifdef ELF_IMAGE
48 static void elf_freebsd_probe(void)
49 {
50         image_type = Elf;
51         if (    (estate.e.elf32.e_entry & 0xf0000000) && 
52                 (estate.e.elf32.e_type == ET_EXEC))
53         {
54                 image_type = Elf_FreeBSD;
55                 printf("/FreeBSD");
56                 off = -(estate.e.elf32.e_entry & 0xff000000);
57                 estate.e.elf32.e_entry += off;
58         }
59         /* Make sure we have a null to start with... */
60         shdr = 0;
61         
62         /* Clear the symbol index values... */
63         symtabindex = -1;
64         symstrindex = -1;
65         
66         /* ...and the load addresses of the symbols  */
67         symtab_load = 0;
68         symstr_load = 0;
69 }
70
71 static void elf_freebsd_fixup_segment(void)
72 {
73         if (image_type == Elf_FreeBSD) {
74                 estate.p.phdr32[estate.segment].p_paddr += off;
75         }
76 }
77
78 static void elf_freebsd_find_segment_end(void)
79 {
80         /* Count the bytes read even for the last block
81          * as we will need to know where the last block
82          * ends in order to load the symbols correctly.
83          * (plus it could be useful elsewhere...)
84          * Note that we need to count the actual size,
85          * not just the end of the disk image size.
86          */
87         estate.curaddr += 
88                 (estate.p.phdr32[estate.segment].p_memsz - 
89                 estate.p.phdr32[estate.segment].p_filesz);
90 }
91
92 static int elf_freebsd_debug_loader(unsigned int offset)
93 {
94         /* No more segments to be loaded - time to start the
95          * nasty state machine to support the loading of
96          * FreeBSD debug symbols due to the fact that FreeBSD
97          * uses/exports the kernel's debug symbols in order
98          * to make much of the system work!  Amazing (arg!)
99          *
100          * We depend on the fact that for the FreeBSD kernel,
101          * there is only one section of debug symbols and that
102          * the section is after all of the loaded sections in
103          * the file.  This assumes a lot but is somewhat required
104          * to make this code not be too annoying.  (Where do you
105          * load symbols when the code has not loaded yet?)
106          * Since this function is actually just a callback from
107          * the network data transfer code, we need to be able to
108          * work with the data as it comes in.  There is no chance
109          * for doing a seek other than forwards.
110          *
111          * The process we use is to first load the section
112          * headers.  Once they are loaded (shdr != 0) we then
113          * look for where the symbol table and symbol table
114          * strings are and setup some state that we found
115          * them and fall into processing the first one (which
116          * is the symbol table) and after that has been loaded,
117          * we try the symbol strings.  Note that the order is
118          * actually required as the memory image depends on
119          * the symbol strings being loaded starting at the
120          * end of the symbol table.  The kernel assumes this
121          * layout of the image.
122          *
123          * At any point, if we get to the end of the load file
124          * or the section requested is earlier in the file than
125          * the current file pointer, we just end up falling
126          * out of this and booting the kernel without this
127          * information.
128          */
129
130         /* Make sure that the next address is long aligned... */
131         /* Assumes size of long is a power of 2... */
132         estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
133         
134         /* If we have not yet gotten the shdr loaded, try that */
135         if (shdr == 0)
136         {
137                 estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
138                 estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
139                 if (estate.toread)
140                 {
141 #if ELF_DEBUG
142                         printf("shdr *, size %lX, curaddr %lX\n", 
143                                 estate.toread, estate.curaddr);
144 #endif
145                         
146                         /* Start reading at the curaddr and make that the shdr */
147                         shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
148                         
149                         /* Start to read... */
150                         return 1;
151                 }
152         }
153         else
154         {
155                 /* We have the shdr loaded, check if we have found
156                  * the indexs where the symbols are supposed to be */
157                 if ((symtabindex == -1) && (symstrindex == -1))
158                 {
159                         int i;
160                         /* Make sure that the address is page aligned... */
161                         /* Symbols need to start in their own page(s)... */
162                         estate.curaddr = (estate.curaddr + 4095) & ~4095;
163                         
164                         /* Need to make new indexes... */
165                         for (i=0; i < estate.e.elf32.e_shnum; i++)
166                         {
167                                 if (shdr[i].sh_type == SHT_SYMTAB)
168                                 {
169                                         int j;
170                                         for (j=0; j < estate.e.elf32.e_phnum; j++)
171                                         {
172                                                 /* Check only for loaded sections */
173                                                 if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
174                                                 {
175                                                         /* Only the extra symbols */
176                                                         if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
177                                                                 ((shdr[i].sh_offset + shdr[i].sh_size) <=
178                                                                         (estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
179                                                         {
180                                                                 shdr[i].sh_offset=0;
181                                                                 shdr[i].sh_size=0;
182                                                                 break;
183                                                         }
184                                                 }
185                                         }
186                                         if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
187                                         {
188                                                 symtabindex = i;
189                                                 symstrindex = shdr[i].sh_link;
190                                         }
191                                 }
192                         }
193                 }
194                 
195                 /* Check if we have a symbol table index and have not loaded it */
196                 if ((symtab_load == 0) && (symtabindex >= 0))
197                 {
198                         /* No symbol table yet?  Load it first... */
199                         
200                         /* This happens to work out in a strange way.
201                          * If we are past the point in the file already,
202                          * we will skip a *large* number of bytes which
203                          * ends up bringing us to the end of the file and
204                          * an old (default) boot.  Less code and lets
205                          * the state machine work in a cleaner way but this
206                          * is a nasty side-effect trick... */
207                         estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
208                         
209                         /* And we need to read this many bytes... */
210                         estate.toread = shdr[symtabindex].sh_size;
211                         
212                         if (estate.toread)
213                         {
214 #if ELF_DEBUG
215                                 printf("db sym, size %lX, curaddr %lX\n", 
216                                         estate.toread, estate.curaddr);
217 #endif
218                                 /* Save where we are loading this... */
219                                 symtab_load = estate.curaddr;
220                                 
221                                 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
222                                 estate.curaddr += sizeof(long);
223                                 
224                                 /* Start to read... */
225                                 return 1;
226                         }
227                 }
228                 else if ((symstr_load == 0) && (symstrindex >= 0))
229                 {
230                         /* We have already loaded the symbol table, so
231                          * now on to the symbol strings... */
232                         
233                         
234                         /* Same nasty trick as above... */
235                         estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
236                         
237                         /* And we need to read this many bytes... */
238                         estate.toread = shdr[symstrindex].sh_size;
239                         
240                         if (estate.toread)
241                         {
242 #if ELF_DEBUG
243                                 printf("db str, size %lX, curaddr %lX\n", 
244                                         estate.toread, estate.curaddr);
245 #endif
246                                 /* Save where we are loading this... */
247                                 symstr_load = estate.curaddr;
248                                 
249                                 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
250                                 estate.curaddr += sizeof(long);
251                                 
252                                 /* Start to read... */
253                                 return 1;
254                         }
255                 }
256         }
257         /* all done */
258         return 0;
259 }
260
261 static void elf_freebsd_boot(unsigned long entry) 
262 {
263         if (image_type != Elf_FreeBSD)
264                 return;
265
266         memset(&bsdinfo, 0, sizeof(bsdinfo));
267         bsdinfo.bi_basemem = meminfo.basememsize;
268         bsdinfo.bi_extmem = meminfo.memsize;
269         bsdinfo.bi_memsizes_valid = 1;
270         bsdinfo.bi_version = BOOTINFO_VERSION;
271         bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
272         bsdinfo.bi_nfs_diskless = NULL;
273         bsdinfo.bi_size = sizeof(bsdinfo);
274 #define RB_BOOTINFO     0x80000000      /* have `struct bootinfo *' arg */  
275         if(freebsd_kernel_env[0] != '\0'){
276                 freebsd_howto |= RB_BOOTINFO;
277                 bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
278         }
279         
280         /* Check if we have symbols loaded, and if so,
281          * made the meta_data needed to pass those to
282          * the kernel. */
283         if ((symtab_load !=0) && (symstr_load != 0))
284         {
285                 unsigned long *t;
286                 
287                 bsdinfo.bi_symtab = symtab_load;
288                 
289                 /* End of symbols (long aligned...) */
290                 /* Assumes size of long is a power of 2... */
291                 bsdinfo.bi_esymtab = (symstr_load +
292                         sizeof(long) +
293                         *((long *)phys_to_virt(symstr_load)) +
294                         sizeof(long) - 1) & ~(sizeof(long) - 1);
295                 
296                 /* Where we will build the meta data... */
297                 t = phys_to_virt(bsdinfo.bi_esymtab);
298                 
299 #if ELF_DEBUG
300                 printf("Metadata at %lX\n",t);
301 #endif
302                 
303                 /* Set up the pointer to the memory... */
304                 bsdinfo.bi_modulep = virt_to_phys(t);
305                 
306                 /* The metadata structure is an array of 32-bit
307                  * words where we store some information about the
308                  * system.  This is critical, as FreeBSD now looks
309                  * only for the metadata for the extended symbol
310                  * information rather than in the bootinfo.
311                  */
312                 /* First, do the kernel name and the kernel type */
313                 /* Note that this assumed x86 byte order... */
314                 
315                 /* 'kernel\0\0' */
316                 *t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
317                 
318                 /* 'elf kernel\0\0' */
319                 *t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
320                 
321                 /* Now the symbol start/end - note that they are
322                  * here in local/physical address - the Kernel
323                  * boot process will relocate the addresses. */
324                 *t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
325                 *t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
326                 
327                 *t++=MODINFO_END; *t++=0; /* end of metadata */
328                 
329                 /* Since we have symbols we need to make
330                  * sure that the kernel knows its own end
331                  * of memory...  It is not _end but after
332                  * the symbols and the metadata... */
333                 bsdinfo.bi_kernend = virt_to_phys(t);
334                 
335                 /* Signal locore.s that we have a valid bootinfo
336                  * structure that was completely filled in. */
337                 freebsd_howto |= 0x80000000;
338         }
339         
340         xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, 
341                 virt_to_phys(&bsdinfo), 0, 0, 0);
342         longjmp(restart_etherboot, -2);
343 }
344 #endif
345
346 #ifdef AOUT_IMAGE
347 static void aout_freebsd_probe(void)
348 {
349         image_type = Aout;
350         if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
351                 /* Some other a.out variants have a different
352                  * value, and use other alignments (e.g. 1K),
353                  * not the 4K used by FreeBSD.  */
354                 image_type = Aout_FreeBSD;
355                 printf("/FreeBSD");
356                 off = -(astate.head.a_entry & 0xff000000);
357                 astate.head.a_entry += off;
358         }
359 }
360
361 static void aout_freebsd_boot(void)
362 {
363         if (image_type == Aout_FreeBSD) {
364                 memset(&bsdinfo, 0, sizeof(bsdinfo));
365                 bsdinfo.bi_basemem = meminfo.basememsize;
366                 bsdinfo.bi_extmem = meminfo.memsize;
367                 bsdinfo.bi_memsizes_valid = 1;
368                 bsdinfo.bi_version = BOOTINFO_VERSION;
369                 bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
370                 bsdinfo.bi_nfs_diskless = NULL;
371                 bsdinfo.bi_size = sizeof(bsdinfo);
372                 xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, 
373                         virt_to_phys(&bsdinfo), 0, 0, 0);
374                 longjmp(restart_etherboot, -2);
375         }
376 }
377 #endif