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 (module
+ e
.e_shoff
), e
.e_shoff
,
201 e
.e_shnum
* e
.e_shentsize
);
202 if (curload
< module
+ e
.e_shoff
+ e
.e_shnum
* e
.e_shentsize
)
203 curload
= module
+ e
.e_shoff
+ e
.e_shnum
* e
.e_shentsize
;
205 load (file
, UINT_TO_PTR (module
+ e
.e_phoff
), e
.e_phoff
,
206 e
.e_phnum
* e
.e_phentsize
);
207 if (curload
< module
+ e
.e_phoff
+ e
.e_phnum
* e
.e_phentsize
)
208 curload
= module
+ e
.e_phoff
+ 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
;