1
#include <grub/loader.h>
2
#include <grub/cpu/bsd.h>
6
#include <grub/i386/loader.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 (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size)
14
return grub_error (GRUB_ERR_OUT_OF_RANGE,
15
"not enough memory for the module");
16
if (grub_file_seek (file, off) == (grub_off_t) -1)
18
if (grub_file_read (file, where, size)
19
!= (grub_ssize_t) size)
24
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
29
static inline grub_err_t
30
read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr)
32
if (grub_file_seek (file, 0) == (grub_off_t) -1)
35
if (grub_file_read (file, (char *) e, sizeof (*e)) != sizeof (*e))
40
return grub_error (GRUB_ERR_BAD_OS, "file is too short");
43
if (e->e_ident[EI_MAG0] != ELFMAG0
44
|| e->e_ident[EI_MAG1] != ELFMAG1
45
|| e->e_ident[EI_MAG2] != ELFMAG2
46
|| e->e_ident[EI_MAG3] != ELFMAG3
47
|| e->e_ident[EI_VERSION] != EV_CURRENT
48
|| e->e_version != EV_CURRENT)
49
return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
51
if (e->e_ident[EI_CLASS] != SUFFIX (ELFCLASS))
52
return grub_error (GRUB_ERR_BAD_OS, "invalid arch dependent ELF magic");
54
*shdr = grub_malloc (e->e_shnum * e->e_shentsize);
58
if (grub_file_seek (file, e->e_shoff) == (grub_off_t) -1)
61
if (grub_file_read (file, *shdr, e->e_shnum * e->e_shentsize)
62
!= e->e_shnum * e->e_shentsize)
67
return grub_error (GRUB_ERR_BAD_OS, "file is truncated");
73
/* On i386 FreeBSD uses "elf module" approarch for 32-bit variant
74
and "elf obj module" for 64-bit variant. However it may differ on other
75
platforms. So I keep both versions. */
78
SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc,
79
char *argv[], grub_addr_t *kern_end)
84
grub_addr_t curload, module;
87
err = read_headers (file, &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
curload = ALIGN_UP (curload, s->sh_addralign);
102
s->sh_addr = curload;
104
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
105
(unsigned) curload, (int) s->sh_size,
106
(int) s->sh_addralign);
112
err = load (file, UINT_TO_PTR (curload), s->sh_offset, s->sh_size);
117
if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size)
118
return grub_error (GRUB_ERR_OUT_OF_RANGE,
119
"not enough memory for the module");
120
grub_memset (UINT_TO_PTR (curload), 0, s->sh_size);
123
curload += s->sh_size;
126
*kern_end = ALIGN_PAGE (curload);
128
err = grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE_OBJ,
129
argc - 1, argv + 1, module,
132
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
133
| FREEBSD_MODINFOMD_ELFHDR,
136
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA
137
| FREEBSD_MODINFOMD_SHDR,
138
shdr, e.e_shnum * e.e_shentsize);
146
SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[],
147
grub_addr_t *kern_end)
152
grub_addr_t curload, module;
155
err = read_headers (file, &e, &shdr);
159
curload = module = ALIGN_PAGE (*kern_end);
161
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr
162
+ e.e_shnum * e.e_shentsize);
163
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
168
if (! (s->sh_flags & SHF_ALLOC))
171
grub_dprintf ("bsd", "loading section to %x, size %d, align %d\n",
172
(unsigned) curload, (int) s->sh_size,
173
(int) s->sh_addralign);
179
err = load (file, UINT_TO_PTR (module + s->sh_addr),
180
s->sh_offset, s->sh_size);
185
if (module + s->sh_addr + s->sh_size
186
> grub_os_area_addr + grub_os_area_size)
187
return grub_error (GRUB_ERR_OUT_OF_RANGE,
188
"not enough memory for the module");
189
grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size);
192
if (curload < module + s->sh_addr + s->sh_size)
193
curload = module + s->sh_addr + s->sh_size;
196
load (file, UINT_TO_PTR (module), 0, sizeof (e));
197
if (curload < module + sizeof (e))
198
curload = module + sizeof (e);
200
load (file, UINT_TO_PTR (curload), e.e_shoff,
201
e.e_shnum * e.e_shentsize);
202
e.e_shoff = curload - module;
203
curload += e.e_shnum * e.e_shentsize;
205
load (file, UINT_TO_PTR (curload), e.e_phoff,
206
e.e_phnum * e.e_phentsize);
207
e.e_phoff = curload - module;
208
curload += e.e_phnum * e.e_phentsize;
212
grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE,
213
argc - 1, argv + 1, module,
215
return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end);
221
SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end)
227
unsigned symoff, stroff, symsize, strsize;
229
grub_freebsd_addr_t symstart, symend, symentsize, dynamic;
234
err = read_headers (file, &e, &shdr);
238
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
239
FREEBSD_MODINFOMD_ELFHDR, &e,
244
for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr
245
+ e.e_shnum * e.e_shentsize);
246
s = (Elf_Shdr *) ((char *) s + e.e_shentsize))
247
if (s->sh_type == SHT_SYMTAB)
249
if (s >= (Elf_Shdr *) ((char *) shdr
250
+ e.e_shnum * e.e_shentsize))
251
return grub_error (GRUB_ERR_BAD_OS, "no symbol table");
252
symoff = s->sh_offset;
253
symsize = s->sh_size;
254
symentsize = s->sh_entsize;
255
s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link);
256
stroff = s->sh_offset;
257
strsize = s->sh_size;
259
if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize
260
> grub_os_area_addr + grub_os_area_size)
261
return grub_error (GRUB_ERR_OUT_OF_RANGE,
262
"not enough memory for kernel symbols");
264
symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t));
265
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize;
266
curload += sizeof (grub_freebsd_addr_t);
267
if (grub_file_seek (file, symoff) == (grub_off_t) -1)
269
sym = (Elf_Sym *) UINT_TO_PTR (curload);
270
if (grub_file_read (file, UINT_TO_PTR (curload), symsize) !=
271
(grub_ssize_t) symsize)
274
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
279
*((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize;
280
curload += sizeof (grub_freebsd_addr_t);
281
if (grub_file_seek (file, stroff) == (grub_off_t) -1)
283
str = (char *) UINT_TO_PTR (curload);
284
if (grub_file_read (file, UINT_TO_PTR (curload), strsize)
285
!= (grub_ssize_t) strsize)
288
return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
292
curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t));
296
i * symentsize < symsize;
297
i++, sym = (Elf_Sym *) ((char *) sym + symentsize))
299
const char *name = str + sym->st_name;
300
if (grub_strcmp (name, "_DYNAMIC") == 0)
304
if (i * symentsize < symsize)
306
dynamic = sym->st_value;
307
grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic);
308
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
309
FREEBSD_MODINFOMD_DYNAMIC, &dynamic,
315
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
316
FREEBSD_MODINFOMD_SSYM, &symstart,
321
err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA |
322
FREEBSD_MODINFOMD_ESYM, &symend,
326
*kern_end = ALIGN_PAGE (curload);
328
return GRUB_ERR_NONE;