[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / arch / i386 / core / freebsd_loader.c
blob464f6d9392e017ce458ef3bfcf2649002167a3f9
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
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 */
30 static struct bootinfo bsdinfo;
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
40 static enum {
41 Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
42 } image_type = Unknown;
44 static unsigned int off;
47 #ifdef ELF_IMAGE
48 static void elf_freebsd_probe(void)
50 image_type = Elf;
51 if ( (estate.e.elf32.e_entry & 0xf0000000) &&
52 (estate.e.elf32.e_type == ET_EXEC))
54 image_type = Elf_FreeBSD;
55 printf("/FreeBSD");
56 off = -(estate.e.elf32.e_entry & 0xff000000);
57 estate.e.elf32.e_entry += off;
59 /* Make sure we have a null to start with... */
60 shdr = 0;
62 /* Clear the symbol index values... */
63 symtabindex = -1;
64 symstrindex = -1;
66 /* ...and the load addresses of the symbols */
67 symtab_load = 0;
68 symstr_load = 0;
71 static void elf_freebsd_fixup_segment(void)
73 if (image_type == Elf_FreeBSD) {
74 estate.p.phdr32[estate.segment].p_paddr += off;
78 static void elf_freebsd_find_segment_end(void)
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.
87 estate.curaddr +=
88 (estate.p.phdr32[estate.segment].p_memsz -
89 estate.p.phdr32[estate.segment].p_filesz);
92 static int elf_freebsd_debug_loader(unsigned int offset)
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!)
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.
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.
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.
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);
134 /* If we have not yet gotten the shdr loaded, try that */
135 if (shdr == 0)
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)
141 #if ELF_DEBUG
142 printf("shdr *, size %lX, curaddr %lX\n",
143 estate.toread, estate.curaddr);
144 #endif
146 /* Start reading at the curaddr and make that the shdr */
147 shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
149 /* Start to read... */
150 return 1;
153 else
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))
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;
164 /* Need to make new indexes... */
165 for (i=0; i < estate.e.elf32.e_shnum; i++)
167 if (shdr[i].sh_type == SHT_SYMTAB)
169 int j;
170 for (j=0; j < estate.e.elf32.e_phnum; j++)
172 /* Check only for loaded sections */
173 if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
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)))
180 shdr[i].sh_offset=0;
181 shdr[i].sh_size=0;
182 break;
186 if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
188 symtabindex = i;
189 symstrindex = shdr[i].sh_link;
195 /* Check if we have a symbol table index and have not loaded it */
196 if ((symtab_load == 0) && (symtabindex >= 0))
198 /* No symbol table yet? Load it first... */
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);
209 /* And we need to read this many bytes... */
210 estate.toread = shdr[symtabindex].sh_size;
212 if (estate.toread)
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;
221 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
222 estate.curaddr += sizeof(long);
224 /* Start to read... */
225 return 1;
228 else if ((symstr_load == 0) && (symstrindex >= 0))
230 /* We have already loaded the symbol table, so
231 * now on to the symbol strings... */
234 /* Same nasty trick as above... */
235 estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
237 /* And we need to read this many bytes... */
238 estate.toread = shdr[symstrindex].sh_size;
240 if (estate.toread)
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;
249 *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
250 estate.curaddr += sizeof(long);
252 /* Start to read... */
253 return 1;
257 /* all done */
258 return 0;
261 static void elf_freebsd_boot(unsigned long entry)
263 if (image_type != Elf_FreeBSD)
264 return;
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;
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))
285 unsigned long *t;
287 bsdinfo.bi_symtab = symtab_load;
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);
296 /* Where we will build the meta data... */
297 t = phys_to_virt(bsdinfo.bi_esymtab);
299 #if ELF_DEBUG
300 printf("Metadata at %lX\n",t);
301 #endif
303 /* Set up the pointer to the memory... */
304 bsdinfo.bi_modulep = virt_to_phys(t);
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.
312 /* First, do the kernel name and the kernel type */
313 /* Note that this assumed x86 byte order... */
315 /* 'kernel\0\0' */
316 *t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
318 /* 'elf kernel\0\0' */
319 *t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
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;
327 *t++=MODINFO_END; *t++=0; /* end of metadata */
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);
335 /* Signal locore.s that we have a valid bootinfo
336 * structure that was completely filled in. */
337 freebsd_howto |= 0x80000000;
340 xstart32(entry, freebsd_howto, NODEV, 0, 0, 0,
341 virt_to_phys(&bsdinfo), 0, 0, 0);
342 longjmp(restart_etherboot, -2);
344 #endif
346 #ifdef AOUT_IMAGE
347 static void aout_freebsd_probe(void)
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;
361 static void aout_freebsd_boot(void)
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);
377 #endif