1
#include <grub/loader.h>
2
#include <grub/i386/bsd.h>
6
#include <grub/i386/relocator.h>
8
#define ALIGN_PAGE(a) ALIGN_UP (a, 4096)
10
static inline grub_err_t
11
load (grub_file_t file, void *where, grub_off_t off, grub_size_t size)
13
if (grub_file_seek (file, off) == (grub_off_t) -1)
15
if (grub_file_read (file, where, size) != (grub_ssize_t) size)
20
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
25
static inline grub_err_t
26
read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr)
28
if (grub_file_seek (file, 0) == (grub_off_t) -1)
31
if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
36
return grub_error (GRUB_ERR_BAD_OS, "file is too short");
39
if (e->e_ident[EI_MAG0] != ELFMAG0
40
|| e->e_ident[EI_MAG1] != ELFMAG1
41
|| e->e_ident[EI_MAG2] != ELFMAG2
42
|| e->e_ident[EI_MAG3] != ELFMAG3
43
|| e->e_ident[EI_VERSION] != EV_CURRENT
44
|| e->e_version != EV_CURRENT)
45
return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
47
if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
48
return grub_error (GRUB_ERR_BAD_OS, "invalid arch dependent ELF magic");
50
*shdr = grub_malloc (e->e_shnum * e->e_shentsize);
54
if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
57
if (grub_file_read (file, *shdr, e->e_shnum * e->e_shentsize)
58
!= e->e_shnum * e->e_shentsize)
63
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
69
/* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
70
and "elf obj module" for 64-bit variant. However it may differ on other
71
platforms. So I keep both versions. */
74
SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator,
75
grub_file_t file, int argc,
76
char *argv[], grub_addr_t *kern_end)
81
grub_addr_t curload, module;
83
grub_size_t chunk_size = 0;
86
err = read_headers (file, &e, &shdr);
90
curload = module = ALIGN_PAGE (*kern_end);
92
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
93
+ e.e_shnum * e.e_shentsize);
94
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
100
chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign)
103
chunk_size += s->sh_size;
107
grub_relocator_chunk_t ch;
108
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
112
chunk_src = get_virtual_current_address (ch);
115
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
116
+ e.e_shnum * e.e_shentsize);
117
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
123
curload = ALIGN_UP (curload, s->sh_addralign);
124
s->sh_addr = curload;
126
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
127
(unsigned) curload, (int) s->sh_size,
128
(int) s->sh_addralign);
134
err = load (file, (grub_uint8_t *) chunk_src + curload - *kern_end,
135
s->sh_offset, s->sh_size);
140
grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0,
144
curload += s->sh_size;
147
*kern_end = ALIGN_PAGE (curload);
149
err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
150
argc - 1, argv + 1, module,
153
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
154
| FREEBSD_MODINFOMD_ELFHDR,
157
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
158
| FREEBSD_MODINFOMD_SHDR,
159
shdr, e.e_shnum * e.e_shentsize);
167
SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator,
168
grub_file_t file, int argc, char *argv[],
169
grub_addr_t *kern_end)
174
grub_addr_t curload, module;
176
grub_size_t chunk_size = 0;
179
err = read_headers (file, &e, &shdr);
183
curload = module = ALIGN_PAGE (*kern_end);
185
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
186
+ e.e_shnum * e.e_shentsize);
187
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
192
if (! (s->sh_flags & SHF_ALLOC))
194
if (chunk_size < s->sh_addr + s->sh_size)
195
chunk_size = s->sh_addr + s->sh_size;
199
grub_relocator_chunk_t ch;
201
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
206
chunk_src = get_virtual_current_address (ch);
209
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
210
+ e.e_shnum * e.e_shentsize);
211
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
216
if (! (s->sh_flags & SHF_ALLOC))
219
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
220
(unsigned) curload, (int) s->sh_size,
221
(int) s->sh_addralign);
227
err = load (file, (grub_uint8_t *) chunk_src + module
228
+ s->sh_addr - *kern_end,
229
s->sh_offset, s->sh_size);
234
grub_memset ((grub_uint8_t *) chunk_src + module
235
+ s->sh_addr - *kern_end, 0, s->sh_size);
238
if (curload < module + s->sh_addr + s->sh_size)
239
curload = module + s->sh_addr + s->sh_size;
242
load (file, UINT_TO_PTR (module), 0, sizeof (e));
243
if (curload < module + sizeof (e))
244
curload = module + sizeof (e);
246
load (file, UINT_TO_PTR (curload), e.e_shoff,
247
e.e_shnum * e.e_shentsize);
248
e.e_shoff = curload - module;
249
curload += e.e_shnum * e.e_shentsize;
251
load (file, UINT_TO_PTR (curload), e.e_phoff,
252
e.e_phnum * e.e_phentsize);
253
e.e_phoff = curload - module;
254
curload += e.e_phnum * e.e_phentsize;
258
grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
259
argc - 1, argv + 1, module,
261
return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, kern_end);
267
SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator,
268
grub_file_t file, grub_addr_t *kern_end)
274
unsigned symoff, stroff, symsize, strsize;
275
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
278
grub_uint8_t *curload;
279
grub_freebsd_addr_t symtarget;
282
grub_size_t chunk_size;
284
err = read_headers (file, &e, &shdr);
288
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
289
FREEBSD_MODINFOMD_ELFHDR, &e,
294
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
295
+ e.e_shnum * e.e_shentsize);
296
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
297
if (s->sh_type == SHT_SYMTAB)
299
if (s >= (Elf_Shdr *) ((char *) shdr
300
+ e.e_shnum * e.e_shentsize))
301
return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
302
symoff = s->sh_offset;
303
symsize = s->sh_size;
304
symentsize = s->sh_entsize;
305
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
306
stroff = s->sh_offset;
307
strsize = s->sh_size;
309
chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t))
310
+ 2 * sizeof (grub_freebsd_addr_t);
312
symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
315
grub_relocator_chunk_t ch;
316
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
317
symtarget, chunk_size);
320
sym_chunk = get_virtual_current_address (ch);
323
symstart = symtarget;
324
symend = symstart + chunk_size;
327
*((grub_freebsd_addr_t *) curload) = symsize;
328
curload += sizeof (grub_freebsd_addr_t);
330
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
332
sym = (Elf_Sym *) curload;
333
if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
336
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
341
*((grub_freebsd_addr_t *) curload) = strsize;
342
curload += sizeof (grub_freebsd_addr_t);
343
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
345
str = (char *) curload;
346
if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
349
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
354
i * symentsize < symsize;
355
i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
357
const char *name = str + sym->st_name;
358
if (grub_strcmp (name, "_DYNAMIC") == 0)
362
if (i * symentsize < symsize)
364
dynamic = sym->st_value;
365
grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
366
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
367
FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
373
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
374
FREEBSD_MODINFOMD_SSYM, &symstart,
379
err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
380
FREEBSD_MODINFOMD_ESYM, &symend,
385
*kern_end = ALIGN_PAGE (symend);
387
return GRUB_ERR_NONE;
391
SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator,
392
grub_file_t file, grub_addr_t *kern_end)
396
Elf_Shdr *s, *symsh, *strsh;
398
unsigned symsize, strsize;
400
grub_uint8_t *curload;
401
grub_size_t chunk_size;
403
struct grub_netbsd_btinfo_symtab symtab;
404
grub_addr_t symtarget;
406
err = read_headers (file, &e, &shdr);
410
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
411
+ e.e_shnum * e.e_shentsize);
412
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
413
if (s->sh_type == SHT_SYMTAB)
415
if (s >= (Elf_Shdr *) ((char *) shdr
416
+ e.e_shnum * e.e_shentsize))
417
return GRUB_ERR_NONE;
418
symsize = s->sh_size;
420
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
421
strsize = s->sh_size;
424
chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
425
+ ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t))
426
+ sizeof (e) + e.e_shnum * e.e_shentsize;
428
symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
430
grub_relocator_chunk_t ch;
431
err = grub_relocator_alloc_chunk_addr (relocator, &ch,
432
symtarget, chunk_size);
435
sym_chunk = get_virtual_current_address (ch);
439
symtab.ssyms = symtarget;
440
symtab.esyms = symtarget + chunk_size;
444
e2 = (Elf_Ehdr *) curload;
445
grub_memcpy (curload, &e, sizeof (e));
450
e2->e_shoff = sizeof (e);
452
curload += sizeof (e);
454
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
455
+ e.e_shnum * e.e_shentsize);
456
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
459
s2 = (Elf_Shdr *) curload;
460
grub_memcpy (curload, s, e.e_shentsize);
462
s2->sh_offset = sizeof (e) + e.e_shnum * e.e_shentsize;
464
s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t))
465
+ sizeof (e) + e.e_shnum * e.e_shentsize;
468
s2->sh_addr = s2->sh_offset;
469
curload += e.e_shentsize;
472
if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1)
474
if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize)
477
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
480
curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t));
482
if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1)
484
if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize)
487
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
491
err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB,
497
*kern_end = ALIGN_PAGE (symtarget + chunk_size);
499
return GRUB_ERR_NONE;
503
SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file,
504
grub_addr_t kern_start,
505
void *kern_chunk_src,
506
struct grub_openbsd_ramdisk_descriptor *desc)
508
unsigned symoff, stroff, symsize, strsize, symentsize;
516
err = read_headers (file, &e, &shdr);
520
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
521
+ e.e_shnum * e.e_shentsize);
522
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
523
if (s->sh_type == SHT_SYMTAB)
525
if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize))
528
return GRUB_ERR_NONE;
531
symsize = s->sh_size;
532
symentsize = s->sh_entsize;
533
symoff = s->sh_offset;
535
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
536
stroff = s->sh_offset;
537
strsize = s->sh_size;
541
Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL;
545
syms = grub_malloc (symsize);
549
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
554
if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize)
558
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
562
strs = grub_malloc (strsize);
569
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
571
if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize)
576
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
580
for (i = 0, sym = syms; i < symsize / symentsize;
581
i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
583
if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT)
587
if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0)
589
if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0)
591
if (imagesym && sizesym)
594
if (!imagesym || !sizesym)
598
return GRUB_ERR_NONE;
600
if (sizeof (*desc->size) != sizesym->st_size)
604
return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size");
606
desc->max_size = imagesym->st_size;
607
desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start
608
+ (grub_uint8_t *) kern_chunk_src;
609
desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start
610
+ (grub_uint8_t *) kern_chunk_src);
614
return GRUB_ERR_NONE;