Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / loader / i386 / bsdXX.c
blob9e36cd4b6510bfb166defefb89d20e02d9e60e72
1 #include <grub/loader.h>
2 #include <grub/i386/bsd.h>
3 #include <grub/mm.h>
4 #include <grub/elf.h>
5 #include <grub/misc.h>
6 #include <grub/i386/relocator.h>
7 #include <grub/i18n.h>
9 #define ALIGN_PAGE(a) ALIGN_UP (a, 4096)
11 static inline grub_err_t
12 load (grub_file_t file, const char *filename, void *where, grub_off_t off, grub_size_t size)
14 if (grub_file_seek (file, off) == (grub_off_t) -1)
15 return grub_errno;
16 if (grub_file_read (file, where, size) != (grub_ssize_t) size)
18 if (grub_errno)
19 return grub_errno;
20 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
21 filename);
23 return GRUB_ERR_NONE;
26 static inline grub_err_t
27 read_headers (grub_file_t file, const char *filename, Elf_Ehdr *e, char **shdr)
29 if (grub_file_seek (file, 0) == (grub_off_t) -1)
30 return grub_errno;
32 if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
34 if (grub_errno)
35 return grub_errno;
36 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
37 filename);
40 if (e->e_ident[EI_MAG0] != ELFMAG0
41 || e->e_ident[EI_MAG1] != ELFMAG1
42 || e->e_ident[EI_MAG2] != ELFMAG2
43 || e->e_ident[EI_MAG3] != ELFMAG3
44 || e->e_ident[EI_VERSION] != EV_CURRENT
45 || e->e_version != EV_CURRENT)
46 return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
48 if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
49 return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
51 *shdr = grub_malloc (e->e_shnum * e->e_shentsize);
52 if (! *shdr)
53 return grub_errno;
55 if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
56 return grub_errno;
58 if (grub_file_read (file, *shdr, e->e_shnum * e->e_shentsize)
59 != e->e_shnum * e->e_shentsize)
61 if (grub_errno)
62 return grub_errno;
63 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
64 filename);
67 return GRUB_ERR_NONE;
70 /* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
71 and "elf obj module" for 64-bit variant. However it may differ on other
72 platforms. So I keep both versions. */
73 #if OBJSYM
74 grub_err_t
75 SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator,
76 grub_file_t file, int argc,
77 char *argv[], grub_addr_t *kern_end)
79 Elf_Ehdr e;
80 Elf_Shdr *s;
81 char *shdr = 0;
82 grub_addr_t curload, module;
83 grub_err_t err;
84 grub_size_t chunk_size = 0;
85 void *chunk_src;
87 err = read_headers (file, argv[0], &e, &shdr);
88 if (err)
89 return err;
91 curload = module = ALIGN_PAGE (*kern_end);
93 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
94 + e.e_shnum * e.e_shentsize);
95 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
97 if (s->sh_size == 0)
98 continue;
100 if (s->sh_addralign)
101 chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign)
102 - *kern_end;
104 chunk_size += s->sh_size;
108 grub_relocator_chunk_t ch;
109 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
110 module, chunk_size);
111 if (err)
112 return err;
113 chunk_src = get_virtual_current_address (ch);
116 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
117 + e.e_shnum * e.e_shentsize);
118 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
120 if (s->sh_size == 0)
121 continue;
123 if (s->sh_addralign)
124 curload = ALIGN_UP (curload, s->sh_addralign);
125 s->sh_addr = curload;
127 grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
128 (unsigned) curload, (int) s->sh_size,
129 (int) s->sh_addralign);
131 switch (s->sh_type)
133 default:
134 case SHT_PROGBITS:
135 err = load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end,
136 s->sh_offset, s->sh_size);
137 if (err)
138 return err;
139 break;
140 case SHT_NOBITS:
141 grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0,
142 s->sh_size);
143 break;
145 curload += s->sh_size;
148 *kern_end = ALIGN_PAGE (curload);
150 err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
151 argc - 1, argv + 1, module,
152 curload - module);
153 if (! err)
154 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
155 | FREEBSD_MODINFOMD_ELFHDR,
156 &e, sizeof (e));
157 if (! err)
158 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
159 | FREEBSD_MODINFOMD_SHDR,
160 shdr, e.e_shnum * e.e_shentsize);
162 return err;
165 #else
167 grub_err_t
168 SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator,
169 grub_file_t file, int argc, char *argv[],
170 grub_addr_t *kern_end)
172 Elf_Ehdr e;
173 Elf_Shdr *s;
174 char *shdr = 0;
175 grub_addr_t curload, module;
176 grub_err_t err;
177 grub_size_t chunk_size = 0;
178 void *chunk_src;
180 err = read_headers (file, argv[0], &e, &shdr);
181 if (err)
182 return err;
184 curload = module = ALIGN_PAGE (*kern_end);
186 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
187 + e.e_shnum * e.e_shentsize);
188 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
190 if (s->sh_size == 0)
191 continue;
193 if (! (s->sh_flags & SHF_ALLOC))
194 continue;
195 if (chunk_size < s->sh_addr + s->sh_size)
196 chunk_size = s->sh_addr + s->sh_size;
199 if (chunk_size < sizeof (e))
200 chunk_size = sizeof (e);
201 chunk_size += e.e_phnum * e.e_phentsize;
202 chunk_size += e.e_shnum * e.e_shentsize;
205 grub_relocator_chunk_t ch;
207 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
208 module, chunk_size);
209 if (err)
210 return err;
212 chunk_src = get_virtual_current_address (ch);
215 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
216 + e.e_shnum * e.e_shentsize);
217 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
219 if (s->sh_size == 0)
220 continue;
222 if (! (s->sh_flags & SHF_ALLOC))
223 continue;
225 grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
226 (unsigned) curload, (int) s->sh_size,
227 (int) s->sh_addralign);
229 switch (s->sh_type)
231 default:
232 case SHT_PROGBITS:
233 err = load (file, argv[0],
234 (grub_uint8_t *) chunk_src + module
235 + s->sh_addr - *kern_end,
236 s->sh_offset, s->sh_size);
237 if (err)
238 return err;
239 break;
240 case SHT_NOBITS:
241 grub_memset ((grub_uint8_t *) chunk_src + module
242 + s->sh_addr - *kern_end, 0, s->sh_size);
243 break;
245 if (curload < module + s->sh_addr + s->sh_size)
246 curload = module + s->sh_addr + s->sh_size;
249 load (file, argv[0], (grub_uint8_t *) chunk_src + module - *kern_end, 0, sizeof (e));
250 if (curload < module + sizeof (e))
251 curload = module + sizeof (e);
253 load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_shoff,
254 e.e_shnum * e.e_shentsize);
255 e.e_shoff = curload - module;
256 curload += e.e_shnum * e.e_shentsize;
258 load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_phoff,
259 e.e_phnum * e.e_phentsize);
260 e.e_phoff = curload - module;
261 curload += e.e_phnum * e.e_phentsize;
263 *kern_end = curload;
265 grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
266 argc - 1, argv + 1, module,
267 curload - module);
268 return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, argv[0], kern_end);
271 #endif
273 grub_err_t
274 SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator,
275 grub_file_t file,
276 const char *filename,
277 grub_addr_t *kern_end)
279 grub_err_t err;
280 Elf_Ehdr e;
281 Elf_Shdr *s;
282 char *shdr = 0;
283 unsigned symoff, stroff, symsize, strsize;
284 grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
285 Elf_Sym *sym;
286 void *sym_chunk;
287 grub_uint8_t *curload;
288 grub_freebsd_addr_t symtarget;
289 const char *str;
290 unsigned i;
291 grub_size_t chunk_size;
293 err = read_headers (file, filename, &e, &shdr);
294 if (err)
295 return err;
297 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
298 FREEBSD_MODINFOMD_ELFHDR, &e,
299 sizeof (e));
300 if (err)
301 return err;
303 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
304 + e.e_shnum * e.e_shentsize);
305 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
306 if (s->sh_type == SHT_SYMTAB)
307 break;
308 if (s >= (Elf_Shdr *) ((char *) shdr
309 + e.e_shnum * e.e_shentsize))
310 return grub_error (GRUB_ERR_BAD_OS, N_("no symbol table"));
311 symoff = s->sh_offset;
312 symsize = s->sh_size;
313 symentsize = s->sh_entsize;
314 s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
315 stroff = s->sh_offset;
316 strsize = s->sh_size;
318 chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t))
319 + 2 * sizeof (grub_freebsd_addr_t);
321 symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
324 grub_relocator_chunk_t ch;
325 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
326 symtarget, chunk_size);
327 if (err)
328 return err;
329 sym_chunk = get_virtual_current_address (ch);
332 symstart = symtarget;
333 symend = symstart + chunk_size;
335 curload = sym_chunk;
336 *((grub_freebsd_addr_t *) curload) = symsize;
337 curload += sizeof (grub_freebsd_addr_t);
339 if (grub_file_seek (file, symoff) == (grub_off_t) -1)
340 return grub_errno;
341 sym = (Elf_Sym *) curload;
342 if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
344 if (! grub_errno)
345 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
346 filename);
347 return grub_errno;
349 curload += symsize;
351 *((grub_freebsd_addr_t *) curload) = strsize;
352 curload += sizeof (grub_freebsd_addr_t);
353 if (grub_file_seek (file, stroff) == (grub_off_t) -1)
354 return grub_errno;
355 str = (char *) curload;
356 if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
358 if (! grub_errno)
359 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
360 filename);
361 return grub_errno;
364 for (i = 0;
365 i * symentsize < symsize;
366 i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
368 const char *name = str + sym->st_name;
369 if (grub_strcmp (name, "_DYNAMIC") == 0)
370 break;
373 if (i * symentsize < symsize)
375 dynamic = sym->st_value;
376 grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
377 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
378 FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
379 sizeof (dynamic));
380 if (err)
381 return err;
384 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
385 FREEBSD_MODINFOMD_SSYM, &symstart,
386 sizeof (symstart));
387 if (err)
388 return err;
390 err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
391 FREEBSD_MODINFOMD_ESYM, &symend,
392 sizeof (symend));
393 if (err)
394 return err;
396 *kern_end = ALIGN_PAGE (symend);
398 return GRUB_ERR_NONE;
401 grub_err_t
402 SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator,
403 grub_file_t file, const char *filename,
404 grub_addr_t *kern_end)
406 grub_err_t err;
407 Elf_Ehdr e;
408 Elf_Shdr *s, *symsh, *strsh;
409 char *shdr = NULL;
410 unsigned symsize, strsize;
411 void *sym_chunk;
412 grub_uint8_t *curload;
413 grub_size_t chunk_size;
414 Elf_Ehdr *e2;
415 struct grub_netbsd_btinfo_symtab symtab;
416 grub_addr_t symtarget;
418 err = read_headers (file, filename, &e, &shdr);
419 if (err)
420 return err;
422 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
423 + e.e_shnum * e.e_shentsize);
424 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
425 if (s->sh_type == SHT_SYMTAB)
426 break;
427 if (s >= (Elf_Shdr *) ((char *) shdr
428 + e.e_shnum * e.e_shentsize))
429 return GRUB_ERR_NONE;
430 symsize = s->sh_size;
431 symsh = s;
432 s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
433 strsize = s->sh_size;
434 strsh = s;
436 chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
437 + ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t))
438 + sizeof (e) + e.e_shnum * e.e_shentsize;
440 symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
442 grub_relocator_chunk_t ch;
443 err = grub_relocator_alloc_chunk_addr (relocator, &ch,
444 symtarget, chunk_size);
445 if (err)
446 return err;
447 sym_chunk = get_virtual_current_address (ch);
450 symtab.nsyms = 1;
451 symtab.ssyms = symtarget;
452 symtab.esyms = symtarget + chunk_size;
454 curload = sym_chunk;
456 e2 = (Elf_Ehdr *) curload;
457 grub_memcpy (curload, &e, sizeof (e));
458 e2->e_phoff = 0;
459 e2->e_phnum = 0;
460 e2->e_phentsize = 0;
461 e2->e_shstrndx = 0;
462 e2->e_shoff = sizeof (e);
464 curload += sizeof (e);
466 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
467 + e.e_shnum * e.e_shentsize);
468 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
470 Elf_Shdr *s2;
471 s2 = (Elf_Shdr *) curload;
472 grub_memcpy (curload, s, e.e_shentsize);
473 if (s == symsh)
474 s2->sh_offset = sizeof (e) + e.e_shnum * e.e_shentsize;
475 else if (s == strsh)
476 s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
477 + sizeof (e) + e.e_shnum * e.e_shentsize;
478 else
479 s2->sh_offset = 0;
480 s2->sh_addr = s2->sh_offset;
481 curload += e.e_shentsize;
484 if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1)
485 return grub_errno;
486 if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
488 if (! grub_errno)
489 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
490 filename);
491 return grub_errno;
493 curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t));
495 if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1)
496 return grub_errno;
497 if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
499 if (! grub_errno)
500 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
501 filename);
502 return grub_errno;
505 err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB,
506 &symtab,
507 sizeof (symtab));
508 if (err)
509 return err;
511 *kern_end = ALIGN_PAGE (symtarget + chunk_size);
513 return GRUB_ERR_NONE;
516 grub_err_t
517 SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file,
518 const char *filename,
519 grub_addr_t kern_start,
520 void *kern_chunk_src,
521 struct grub_openbsd_ramdisk_descriptor *desc)
523 unsigned symoff, stroff, symsize, strsize, symentsize;
526 grub_err_t err;
527 Elf_Ehdr e;
528 Elf_Shdr *s;
529 char *shdr = NULL;
531 err = read_headers (file, filename, &e, &shdr);
532 if (err)
533 return err;
535 for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
536 + e.e_shnum * e.e_shentsize);
537 s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
538 if (s->sh_type == SHT_SYMTAB)
539 break;
540 if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize))
542 grub_free (shdr);
543 return GRUB_ERR_NONE;
546 symsize = s->sh_size;
547 symentsize = s->sh_entsize;
548 symoff = s->sh_offset;
550 s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
551 stroff = s->sh_offset;
552 strsize = s->sh_size;
553 grub_free (shdr);
556 Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL;
557 unsigned i;
558 char *strs;
560 syms = grub_malloc (symsize);
561 if (!syms)
562 return grub_errno;
564 if (grub_file_seek (file, symoff) == (grub_off_t) -1)
566 grub_free (syms);
567 return grub_errno;
569 if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize)
571 grub_free (syms);
572 if (! grub_errno)
573 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
574 filename);
575 return grub_errno;
578 strs = grub_malloc (strsize);
579 if (!strs)
581 grub_free (syms);
582 return grub_errno;
585 if (grub_file_seek (file, stroff) == (grub_off_t) -1)
586 return grub_errno;
587 if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize)
589 grub_free (syms);
590 grub_free (strs);
591 if (! grub_errno)
592 return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
593 filename);
594 return grub_errno;
597 for (i = 0, sym = syms; i * symentsize < symsize;
598 i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
600 if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
601 continue;
602 if (!sym->st_name)
603 continue;
604 if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0)
605 imagesym = sym;
606 if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0)
607 sizesym = sym;
608 if (imagesym && sizesym)
609 break;
611 if (!imagesym || !sizesym)
613 grub_free (syms);
614 grub_free (strs);
615 return GRUB_ERR_NONE;
617 if (sizeof (*desc->size) != sizesym->st_size)
619 grub_free (syms);
620 grub_free (strs);
621 return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size");
623 desc->max_size = imagesym->st_size;
624 desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start
625 + (grub_uint8_t *) kern_chunk_src;
626 desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start
627 + (grub_uint8_t *) kern_chunk_src);
628 grub_free (syms);
629 grub_free (strs);
631 return GRUB_ERR_NONE;