1 /* Load runtime image of EFIemu. Functions specific to 32/64-bit mode */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22 #include <grub/misc.h>
23 #include <grub/efiemu/efiemu.h>
24 #include <grub/cpu/efiemu.h>
25 #include <grub/machine/efiemu.h>
28 /* ELF symbols and their values */
29 static struct grub_efiemu_elf_sym
*grub_efiemu_elfsyms
= 0;
30 static int grub_efiemu_nelfsyms
= 0;
32 /* Return the address of a section whose index is N. */
34 grub_efiemu_get_section_addr (grub_efiemu_segment_t segs
, unsigned n
,
35 int *handle
, grub_off_t
*off
)
37 grub_efiemu_segment_t seg
;
39 for (seg
= segs
; seg
; seg
= seg
->next
)
40 if (seg
->section
== n
)
42 *handle
= seg
->handle
;
47 return grub_error (GRUB_ERR_BAD_OS
, "section %d not found", n
);
51 SUFFIX (grub_efiemu_loadcore_unload
) (void)
53 grub_free (grub_efiemu_elfsyms
);
54 grub_efiemu_elfsyms
= 0;
58 /* Check if EHDR is a valid ELF header. */
60 SUFFIX (grub_efiemu_check_header
) (void *ehdr
, grub_size_t size
)
64 /* Check the header size. */
65 if (size
< sizeof (Elf_Ehdr
))
68 /* Check the magic numbers. */
69 if (!SUFFIX (grub_arch_efiemu_check_header
) (ehdr
)
70 || e
->e_ident
[EI_MAG0
] != ELFMAG0
71 || e
->e_ident
[EI_MAG1
] != ELFMAG1
72 || e
->e_ident
[EI_MAG2
] != ELFMAG2
73 || e
->e_ident
[EI_MAG3
] != ELFMAG3
74 || e
->e_ident
[EI_VERSION
] != EV_CURRENT
75 || e
->e_version
!= EV_CURRENT
)
81 /* Load all segments from memory specified by E. */
83 grub_efiemu_load_segments (grub_efiemu_segment_t segs
, const Elf_Ehdr
*e
)
86 grub_efiemu_segment_t cur
;
88 grub_dprintf ("efiemu", "loading segments\n");
90 for (cur
=segs
; cur
; cur
= cur
->next
)
92 s
= (Elf_Shdr
*)cur
->srcptr
;
94 if ((s
->sh_flags
& SHF_ALLOC
) && s
->sh_size
)
98 addr
= (grub_uint8_t
*) grub_efiemu_mm_obtain_request (cur
->handle
)
104 grub_memcpy (addr
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
107 grub_memset (addr
, 0, s
->sh_size
);
113 return GRUB_ERR_NONE
;
116 /* Get a string at offset OFFSET from strtab */
118 grub_efiemu_get_string (unsigned offset
, const Elf_Ehdr
*e
)
123 for (i
= 0, s
= (Elf_Shdr
*)((char *) e
+ e
->e_shoff
);
125 i
++, s
= (Elf_Shdr
*)((char *) s
+ e
->e_shentsize
))
126 if (s
->sh_type
== SHT_STRTAB
&& offset
< s
->sh_size
)
127 return (char *) e
+ s
->sh_offset
+ offset
;
131 /* Request memory for segments and fill segments info */
133 grub_efiemu_init_segments (grub_efiemu_segment_t
*segs
, const Elf_Ehdr
*e
)
138 for (i
= 0, s
= (Elf_Shdr
*)((char *) e
+ e
->e_shoff
);
140 i
++, s
= (Elf_Shdr
*)((char *) s
+ e
->e_shentsize
))
142 if (s
->sh_flags
& SHF_ALLOC
)
144 grub_efiemu_segment_t seg
;
145 seg
= (grub_efiemu_segment_t
) grub_malloc (sizeof (*seg
));
152 = grub_efiemu_request_memalign
153 (s
->sh_addralign
, s
->sh_size
,
154 s
->sh_flags
& SHF_EXECINSTR
? GRUB_EFI_RUNTIME_SERVICES_CODE
155 : GRUB_EFI_RUNTIME_SERVICES_DATA
);
162 .text-physical doesn't need to be relocated when switching to
165 if (!grub_strcmp (grub_efiemu_get_string (s
->sh_name
, e
),
167 seg
->ptv_rel_needed
= 0;
169 seg
->ptv_rel_needed
= 1;
170 seg
->size
= s
->sh_size
;
178 return GRUB_ERR_NONE
;
181 /* Count symbols and relocators and allocate/request memory for them */
183 grub_efiemu_count_symbols (const Elf_Ehdr
*e
)
190 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
192 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
193 if (s
->sh_type
== SHT_SYMTAB
)
197 return grub_error (GRUB_ERR_BAD_OS
, "no symbol table");
199 grub_efiemu_nelfsyms
= (unsigned) s
->sh_size
/ (unsigned) s
->sh_entsize
;
200 grub_efiemu_elfsyms
= (struct grub_efiemu_elf_sym
*)
201 grub_malloc (sizeof (struct grub_efiemu_elf_sym
) * grub_efiemu_nelfsyms
);
204 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
206 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
207 if (s
->sh_type
== SHT_REL
|| s
->sh_type
== SHT_RELA
)
208 num
+= ((unsigned) s
->sh_size
) / ((unsigned) s
->sh_entsize
);
210 grub_efiemu_request_symbols (num
);
212 return GRUB_ERR_NONE
;
215 /* Fill grub_efiemu_elfsyms with symbol values */
217 grub_efiemu_resolve_symbols (grub_efiemu_segment_t segs
, Elf_Ehdr
*e
)
223 Elf_Word size
, entsize
;
225 grub_dprintf ("efiemu", "resolving symbols\n");
227 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
229 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
230 if (s
->sh_type
== SHT_SYMTAB
)
234 return grub_error (GRUB_ERR_BAD_OS
, "no symbol table");
236 sym
= (Elf_Sym
*) ((char *) e
+ s
->sh_offset
);
238 entsize
= s
->sh_entsize
;
240 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shentsize
* s
->sh_link
);
241 str
= (char *) e
+ s
->sh_offset
;
245 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ entsize
))
247 unsigned char type
= ELF_ST_TYPE (sym
->st_info
);
248 unsigned char bind
= ELF_ST_BIND (sym
->st_info
);
252 const char *name
= str
+ sym
->st_name
;
253 grub_efiemu_elfsyms
[i
].section
= sym
->st_shndx
;
257 /* Resolve a global symbol. */
258 if (sym
->st_name
!= 0 && sym
->st_shndx
== 0)
260 if ((err
= grub_efiemu_resolve_symbol (name
, &handle
, &off
)))
262 grub_efiemu_elfsyms
[i
].handle
= handle
;
263 grub_efiemu_elfsyms
[i
].off
= off
;
270 if ((err
= grub_efiemu_get_section_addr
271 (segs
, sym
->st_shndx
, &handle
, &off
)))
274 off
+= sym
->st_value
;
275 if (bind
!= STB_LOCAL
)
276 if ((err
= grub_efiemu_register_symbol (name
, handle
, off
)))
278 grub_efiemu_elfsyms
[i
].handle
= handle
;
279 grub_efiemu_elfsyms
[i
].off
= off
;
283 if ((err
= grub_efiemu_get_section_addr
284 (segs
, sym
->st_shndx
, &handle
, &off
)))
287 off
+= sym
->st_value
;
288 if (bind
!= STB_LOCAL
)
289 if ((err
= grub_efiemu_register_symbol (name
, handle
, off
)))
291 grub_efiemu_elfsyms
[i
].handle
= handle
;
292 grub_efiemu_elfsyms
[i
].off
= off
;
296 if ((err
= grub_efiemu_get_section_addr
297 (segs
, sym
->st_shndx
, &handle
, &off
)))
299 grub_efiemu_elfsyms
[i
].handle
= 0;
300 grub_efiemu_elfsyms
[i
].off
= 0;
301 grub_errno
= GRUB_ERR_NONE
;
305 grub_efiemu_elfsyms
[i
].handle
= handle
;
306 grub_efiemu_elfsyms
[i
].off
= off
;
310 grub_efiemu_elfsyms
[i
].handle
= 0;
311 grub_efiemu_elfsyms
[i
].off
= 0;
315 return grub_error (GRUB_ERR_BAD_MODULE
,
316 "unknown symbol type `%d'", (int) type
);
320 return GRUB_ERR_NONE
;
323 /* Load runtime to the memory and request memory for definitive location*/
325 SUFFIX (grub_efiemu_loadcore_init
) (void *core
, grub_size_t core_size
,
326 grub_efiemu_segment_t
*segments
)
328 Elf_Ehdr
*e
= (Elf_Ehdr
*) core
;
331 if (e
->e_type
!= ET_REL
)
332 return grub_error (GRUB_ERR_BAD_MODULE
, "invalid ELF file type");
334 /* Make sure that every section is within the core. */
335 if ((grub_size_t
) core_size
< e
->e_shoff
+ e
->e_shentsize
* e
->e_shnum
)
336 return grub_error (GRUB_ERR_BAD_OS
, "ELF sections outside core");
338 if ((err
= grub_efiemu_init_segments (segments
, core
)))
340 if ((err
= grub_efiemu_count_symbols (core
)))
343 grub_efiemu_request_symbols (1);
344 return GRUB_ERR_NONE
;
347 /* Load runtime definitively */
349 SUFFIX (grub_efiemu_loadcore_load
) (void *core
,
350 grub_size_t core_size
351 __attribute__ ((unused
)),
352 grub_efiemu_segment_t segments
)
355 if ((err
= grub_efiemu_load_segments (segments
, core
)))
357 if ((err
= grub_efiemu_resolve_symbols (segments
, core
)))
359 if ((err
= SUFFIX (grub_arch_efiemu_relocate_symbols
) (segments
,
364 return GRUB_ERR_NONE
;