1 #include <grub/loader.h>
2 #include <grub/i386/bsd.h>
6 #include <grub/i386/relocator.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)
16 if (grub_file_read (file
, where
, size
) != (grub_ssize_t
) size
)
20 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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)
32 if (grub_file_read (file
, (char *) e
, sizeof (*e
)) != sizeof (*e
))
36 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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
);
55 if (grub_file_seek (file
, e
->e_shoff
) == (grub_off_t
) -1)
58 if (grub_file_read (file
, *shdr
, e
->e_shnum
* e
->e_shentsize
)
59 != e
->e_shnum
* e
->e_shentsize
)
63 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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. */
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
)
82 grub_addr_t curload
, module
;
84 grub_size_t chunk_size
= 0;
87 err
= read_headers (file
, argv
[0], &e
, &shdr
);
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
))
101 chunk_size
= ALIGN_UP (chunk_size
+ *kern_end
, s
->sh_addralign
)
104 chunk_size
+= s
->sh_size
;
108 grub_relocator_chunk_t ch
;
109 err
= grub_relocator_alloc_chunk_addr (relocator
, &ch
,
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
))
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
);
135 err
= load (file
, argv
[0], (grub_uint8_t
*) chunk_src
+ curload
- *kern_end
,
136 s
->sh_offset
, s
->sh_size
);
141 grub_memset ((grub_uint8_t
*) chunk_src
+ curload
- *kern_end
, 0,
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
,
154 err
= grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
155 | FREEBSD_MODINFOMD_ELFHDR
,
158 err
= grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
159 | FREEBSD_MODINFOMD_SHDR
,
160 shdr
, e
.e_shnum
* e
.e_shentsize
);
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
)
175 grub_addr_t curload
, module
;
177 grub_size_t chunk_size
= 0;
180 err
= read_headers (file
, argv
[0], &e
, &shdr
);
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
))
193 if (! (s
->sh_flags
& SHF_ALLOC
))
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
,
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
))
222 if (! (s
->sh_flags
& SHF_ALLOC
))
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
);
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
);
241 grub_memset ((grub_uint8_t
*) chunk_src
+ module
242 + s
->sh_addr
- *kern_end
, 0, s
->sh_size
);
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
;
265 grub_freebsd_add_meta_module (argv
[0], FREEBSD_MODTYPE_ELF_MODULE
,
266 argc
- 1, argv
+ 1, module
,
268 return SUFFIX (grub_freebsd_load_elf_meta
) (relocator
, file
, argv
[0], kern_end
);
274 SUFFIX (grub_freebsd_load_elf_meta
) (struct grub_relocator
*relocator
,
276 const char *filename
,
277 grub_addr_t
*kern_end
)
283 unsigned symoff
, stroff
, symsize
, strsize
;
284 grub_freebsd_addr_t symstart
, symend
, symentsize
, dynamic
;
287 grub_uint8_t
*curload
;
288 grub_freebsd_addr_t symtarget
;
291 grub_size_t chunk_size
;
293 err
= read_headers (file
, filename
, &e
, &shdr
);
297 err
= grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
|
298 FREEBSD_MODINFOMD_ELFHDR
, &e
,
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
)
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
);
329 sym_chunk
= get_virtual_current_address (ch
);
332 symstart
= symtarget
;
333 symend
= symstart
+ chunk_size
;
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)
341 sym
= (Elf_Sym
*) curload
;
342 if (grub_file_read (file
, curload
, symsize
) != (grub_ssize_t
) symsize
)
345 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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)
355 str
= (char *) curload
;
356 if (grub_file_read (file
, curload
, strsize
) != (grub_ssize_t
) strsize
)
359 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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)
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
,
384 err
= grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
|
385 FREEBSD_MODINFOMD_SSYM
, &symstart
,
390 err
= grub_bsd_add_meta (FREEBSD_MODINFO_METADATA
|
391 FREEBSD_MODINFOMD_ESYM
, &symend
,
396 *kern_end
= ALIGN_PAGE (symend
);
398 return GRUB_ERR_NONE
;
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
)
408 Elf_Shdr
*s
, *symsh
, *strsh
;
410 unsigned symsize
, strsize
;
412 grub_uint8_t
*curload
;
413 grub_size_t chunk_size
;
415 struct grub_netbsd_btinfo_symtab symtab
;
416 grub_addr_t symtarget
;
418 err
= read_headers (file
, filename
, &e
, &shdr
);
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
)
427 if (s
>= (Elf_Shdr
*) ((char *) shdr
428 + e
.e_shnum
* e
.e_shentsize
))
429 return GRUB_ERR_NONE
;
430 symsize
= s
->sh_size
;
432 s
= (Elf_Shdr
*) (shdr
+ e
.e_shentsize
* s
->sh_link
);
433 strsize
= s
->sh_size
;
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
);
447 sym_chunk
= get_virtual_current_address (ch
);
451 symtab
.ssyms
= symtarget
;
452 symtab
.esyms
= symtarget
+ chunk_size
;
456 e2
= (Elf_Ehdr
*) curload
;
457 grub_memcpy (curload
, &e
, sizeof (e
));
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
))
471 s2
= (Elf_Shdr
*) curload
;
472 grub_memcpy (curload
, s
, e
.e_shentsize
);
474 s2
->sh_offset
= sizeof (e
) + e
.e_shnum
* e
.e_shentsize
;
476 s2
->sh_offset
= ALIGN_UP (symsize
, sizeof (grub_freebsd_addr_t
))
477 + sizeof (e
) + e
.e_shnum
* e
.e_shentsize
;
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)
486 if (grub_file_read (file
, curload
, symsize
) != (grub_ssize_t
) symsize
)
489 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
493 curload
+= ALIGN_UP (symsize
, sizeof (grub_freebsd_addr_t
));
495 if (grub_file_seek (file
, strsh
->sh_offset
) == (grub_off_t
) -1)
497 if (grub_file_read (file
, curload
, strsize
) != (grub_ssize_t
) strsize
)
500 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
505 err
= grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB
,
511 *kern_end
= ALIGN_PAGE (symtarget
+ chunk_size
);
513 return GRUB_ERR_NONE
;
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
;
531 err
= read_headers (file
, filename
, &e
, &shdr
);
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
)
540 if (s
>= (Elf_Shdr
*) ((char *) shdr
+ e
.e_shnum
* e
.e_shentsize
))
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
;
556 Elf_Sym
*syms
, *sym
, *imagesym
= NULL
, *sizesym
= NULL
;
560 syms
= grub_malloc (symsize
);
564 if (grub_file_seek (file
, symoff
) == (grub_off_t
) -1)
569 if (grub_file_read (file
, syms
, symsize
) != (grub_ssize_t
) symsize
)
573 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
578 strs
= grub_malloc (strsize
);
585 if (grub_file_seek (file
, stroff
) == (grub_off_t
) -1)
587 if (grub_file_read (file
, strs
, strsize
) != (grub_ssize_t
) strsize
)
592 return grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
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
)
604 if (grub_strcmp (strs
+ sym
->st_name
, "rd_root_image") == 0)
606 if (grub_strcmp (strs
+ sym
->st_name
, "rd_root_size") == 0)
608 if (imagesym
&& sizesym
)
611 if (!imagesym
|| !sizesym
)
615 return GRUB_ERR_NONE
;
617 if (sizeof (*desc
->size
) != sizesym
->st_size
)
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
);
631 return GRUB_ERR_NONE
;