]>
git.proxmox.com Git - grub2.git/blob - grub-core/kern/dl.c
623e0cbcb32637fa6667251d3de6d04e170ae887
1 /* dl.c - loadable module support */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2003,2004,2005,2007,2008,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/>.
20 /* Force native word size */
21 #define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
26 #include <grub/misc.h>
29 #include <grub/types.h>
30 #include <grub/symbol.h>
31 #include <grub/file.h>
33 #include <grub/cache.h>
35 /* Platforms where modules are in a readonly area of memory. */
36 #if defined(GRUB_MACHINE_QEMU)
37 #define GRUB_MODULES_MACHINE_READONLY
42 grub_dl_t grub_dl_head
= 0;
45 grub_dl_add (grub_dl_t mod
)
47 if (grub_dl_get (mod
->name
))
48 return grub_error (GRUB_ERR_BAD_MODULE
,
49 "`%s' is already loaded", mod
->name
);
51 mod
->next
= grub_dl_head
;
58 grub_dl_remove (grub_dl_t mod
)
62 for (p
= &grub_dl_head
, q
= *p
; q
; p
= &q
->next
, q
= *p
)
71 grub_dl_get (const char *name
)
75 for (l
= grub_dl_head
; l
; l
= l
->next
)
76 if (grub_strcmp (name
, l
->name
) == 0)
86 struct grub_symbol
*next
;
89 grub_dl_t mod
; /* The module to which this symbol belongs. */
91 typedef struct grub_symbol
*grub_symbol_t
;
93 /* The size of the symbol table. */
94 #define GRUB_SYMTAB_SIZE 509
96 /* The symbol table (using an open-hash). */
97 static struct grub_symbol
*grub_symtab
[GRUB_SYMTAB_SIZE
];
99 /* Simple hash function. */
101 grub_symbol_hash (const char *s
)
106 key
= key
* 65599 + *s
++;
108 return (key
+ (key
>> 5)) % GRUB_SYMTAB_SIZE
;
111 /* Resolve the symbol name NAME and return the address.
112 Return NULL, if not found. */
114 grub_dl_resolve_symbol (const char *name
)
118 for (sym
= grub_symtab
[grub_symbol_hash (name
)]; sym
; sym
= sym
->next
)
119 if (grub_strcmp (sym
->name
, name
) == 0)
125 /* Register a symbol with the name NAME and the address ADDR. */
127 grub_dl_register_symbol (const char *name
, void *addr
, grub_dl_t mod
)
132 sym
= (grub_symbol_t
) grub_malloc (sizeof (*sym
));
138 sym
->name
= grub_strdup (name
);
151 k
= grub_symbol_hash (name
);
152 sym
->next
= grub_symtab
[k
];
153 grub_symtab
[k
] = sym
;
155 return GRUB_ERR_NONE
;
158 /* Unregister all the symbols defined in the module MOD. */
160 grub_dl_unregister_symbols (grub_dl_t mod
)
165 grub_fatal ("core symbols cannot be unregistered");
167 for (i
= 0; i
< GRUB_SYMTAB_SIZE
; i
++)
169 grub_symbol_t sym
, *p
, q
;
171 for (p
= &grub_symtab
[i
], sym
= *p
; sym
; sym
= q
)
177 grub_free ((void *) sym
->name
);
186 /* Return the address of a section whose index is N. */
188 grub_dl_get_section_addr (grub_dl_t mod
, unsigned n
)
190 grub_dl_segment_t seg
;
192 for (seg
= mod
->segment
; seg
; seg
= seg
->next
)
193 if (seg
->section
== n
)
199 /* Check if EHDR is a valid ELF header. */
201 grub_dl_check_header (void *ehdr
, grub_size_t size
)
205 /* Check the header size. */
206 if (size
< sizeof (Elf_Ehdr
))
207 return grub_error (GRUB_ERR_BAD_OS
, "ELF header smaller than expected");
209 /* Check the magic numbers. */
210 if (grub_arch_dl_check_header (ehdr
)
211 || e
->e_ident
[EI_MAG0
] != ELFMAG0
212 || e
->e_ident
[EI_MAG1
] != ELFMAG1
213 || e
->e_ident
[EI_MAG2
] != ELFMAG2
214 || e
->e_ident
[EI_MAG3
] != ELFMAG3
215 || e
->e_ident
[EI_VERSION
] != EV_CURRENT
216 || e
->e_version
!= EV_CURRENT
)
217 return grub_error (GRUB_ERR_BAD_OS
, "invalid arch independent ELF magic");
219 return GRUB_ERR_NONE
;
222 /* Load all segments from memory specified by E. */
224 grub_dl_load_segments (grub_dl_t mod
, const Elf_Ehdr
*e
)
229 for (i
= 0, s
= (Elf_Shdr
*)((char *) e
+ e
->e_shoff
);
231 i
++, s
= (Elf_Shdr
*)((char *) s
+ e
->e_shentsize
))
233 if (s
->sh_flags
& SHF_ALLOC
)
235 grub_dl_segment_t seg
;
237 seg
= (grub_dl_segment_t
) grub_malloc (sizeof (*seg
));
245 addr
= grub_memalign (s
->sh_addralign
, s
->sh_size
);
255 grub_memcpy (addr
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
258 grub_memset (addr
, 0, s
->sh_size
);
267 seg
->size
= s
->sh_size
;
269 seg
->next
= mod
->segment
;
274 return GRUB_ERR_NONE
;
278 grub_dl_resolve_symbols (grub_dl_t mod
, Elf_Ehdr
*e
)
284 Elf_Word size
, entsize
;
286 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
288 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
289 if (s
->sh_type
== SHT_SYMTAB
)
293 return grub_error (GRUB_ERR_BAD_MODULE
, "no symbol table");
295 #ifdef GRUB_MODULES_MACHINE_READONLY
296 mod
->symtab
= grub_malloc (s
->sh_size
);
297 memcpy (mod
->symtab
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
299 mod
->symtab
= (Elf_Sym
*) ((char *) e
+ s
->sh_offset
);
303 entsize
= s
->sh_entsize
;
305 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shentsize
* s
->sh_link
);
306 str
= (char *) e
+ s
->sh_offset
;
310 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ entsize
))
312 unsigned char type
= ELF_ST_TYPE (sym
->st_info
);
313 unsigned char bind
= ELF_ST_BIND (sym
->st_info
);
314 const char *name
= str
+ sym
->st_name
;
320 /* Resolve a global symbol. */
321 if (sym
->st_name
!= 0 && sym
->st_shndx
== 0)
323 sym
->st_value
= (Elf_Addr
) grub_dl_resolve_symbol (name
);
325 return grub_error (GRUB_ERR_BAD_MODULE
,
326 "symbol not found: `%s'", name
);
330 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
332 if (bind
!= STB_LOCAL
)
333 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
339 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
341 if (bind
!= STB_LOCAL
)
342 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
345 if (grub_strcmp (name
, "grub_mod_init") == 0)
346 mod
->init
= (void (*) (grub_dl_t
)) sym
->st_value
;
347 else if (grub_strcmp (name
, "grub_mod_fini") == 0)
348 mod
->fini
= (void (*) (void)) sym
->st_value
;
352 sym
->st_value
= (Elf_Addr
) grub_dl_get_section_addr (mod
,
361 return grub_error (GRUB_ERR_BAD_MODULE
,
362 "unknown symbol type `%d'", (int) type
);
366 return GRUB_ERR_NONE
;
370 grub_dl_call_init (grub_dl_t mod
)
376 /* Me, Vladimir Serbinenko, hereby I add this module check as per new
377 GNU module policy. Note that this license check is informative only.
378 Modules have to be licensed under GPLv3 or GPLv3+ (optionally
379 multi-licensed under other licences as well) independently of the
380 presence of this check and solely by linking (module loading in GRUB
381 constitutes linking) and GRUB core being licensed under GPLv3+.
382 Be sure to understand your license obligations.
385 grub_dl_check_license (Elf_Ehdr
*e
)
391 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
392 str
= (char *) e
+ s
->sh_offset
;
394 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
396 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
397 if (grub_strcmp (str
+ s
->sh_name
, ".module_license") == 0)
399 if (grub_strcmp ((char *) e
+ s
->sh_offset
, "LICENSE=GPLv3") == 0
400 || grub_strcmp ((char *) e
+ s
->sh_offset
, "LICENSE=GPLv3+") == 0
401 || grub_strcmp ((char *) e
+ s
->sh_offset
, "LICENSE=GPLv2+") == 0)
402 return GRUB_ERR_NONE
;
405 return grub_error (GRUB_ERR_BAD_MODULE
, "incompatible license");
409 grub_dl_resolve_name (grub_dl_t mod
, Elf_Ehdr
*e
)
415 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
416 str
= (char *) e
+ s
->sh_offset
;
418 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
420 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
421 if (grub_strcmp (str
+ s
->sh_name
, ".modname") == 0)
423 mod
->name
= grub_strdup ((char *) e
+ s
->sh_offset
);
430 return grub_error (GRUB_ERR_BAD_MODULE
, "no module name found");
432 return GRUB_ERR_NONE
;
436 grub_dl_resolve_dependencies (grub_dl_t mod
, Elf_Ehdr
*e
)
442 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
443 str
= (char *) e
+ s
->sh_offset
;
445 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
447 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
448 if (grub_strcmp (str
+ s
->sh_name
, ".moddeps") == 0)
450 const char *name
= (char *) e
+ s
->sh_offset
;
451 const char *max
= name
+ s
->sh_size
;
453 while ((name
< max
) && (*name
))
458 m
= grub_dl_load (name
);
464 dep
= (grub_dl_dep_t
) grub_malloc (sizeof (*dep
));
469 dep
->next
= mod
->dep
;
472 name
+= grub_strlen (name
) + 1;
476 return GRUB_ERR_NONE
;
480 grub_dl_ref (grub_dl_t mod
)
487 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
488 grub_dl_ref (dep
->mod
);
490 return ++mod
->ref_count
;
494 grub_dl_unref (grub_dl_t mod
)
501 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
502 grub_dl_unref (dep
->mod
);
504 return --mod
->ref_count
;
508 grub_dl_flush_cache (grub_dl_t mod
)
510 grub_dl_segment_t seg
;
512 for (seg
= mod
->segment
; seg
; seg
= seg
->next
) {
514 grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
515 (unsigned long) seg
->size
, seg
->addr
);
516 grub_arch_sync_caches (seg
->addr
, seg
->size
);
521 /* Load a module from core memory. */
523 grub_dl_load_core (void *addr
, grub_size_t size
)
528 grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr
,
529 (unsigned long) size
);
531 if (grub_dl_check_header (e
, size
))
534 if (e
->e_type
!= ET_REL
)
536 grub_error (GRUB_ERR_BAD_MODULE
, "invalid ELF file type");
540 /* Make sure that every section is within the core. */
541 if (size
< e
->e_shoff
+ e
->e_shentsize
* e
->e_shnum
)
543 grub_error (GRUB_ERR_BAD_OS
, "ELF sections outside core");
547 mod
= (grub_dl_t
) grub_zalloc (sizeof (*mod
));
553 grub_dprintf ("modules", "relocating to %p\n", mod
);
554 /* Me, Vladimir Serbinenko, hereby I add this module check as per new
555 GNU module policy. Note that this license check is informative only.
556 Modules have to be licensed under GPLv3 or GPLv3+ (optionally
557 multi-licensed under other licences as well) independently of the
558 presence of this check and solely by linking (module loading in GRUB
559 constitutes linking) and GRUB core being licensed under GPLv3+.
560 Be sure to understand your license obligations.
562 if (grub_dl_check_license (e
)
563 || grub_dl_resolve_name (mod
, e
)
564 || grub_dl_resolve_dependencies (mod
, e
)
565 || grub_dl_load_segments (mod
, e
)
566 || grub_dl_resolve_symbols (mod
, e
)
567 || grub_arch_dl_relocate_symbols (mod
, e
))
570 grub_dl_unload (mod
);
574 grub_dl_flush_cache (mod
);
576 grub_dprintf ("modules", "module name: %s\n", mod
->name
);
577 grub_dprintf ("modules", "init function: %p\n", mod
->init
);
578 grub_dl_call_init (mod
);
580 if (grub_dl_add (mod
))
582 grub_dl_unload (mod
);
589 /* Load a module from the file FILENAME. */
591 grub_dl_load_file (const char *filename
)
593 grub_file_t file
= NULL
;
598 file
= grub_file_open (filename
);
602 size
= grub_file_size (file
);
603 core
= grub_malloc (size
);
606 grub_file_close (file
);
610 if (grub_file_read (file
, core
, size
) != (int) size
)
612 grub_file_close (file
);
617 /* We must close this before we try to process dependencies.
618 Some disk backends do not handle gracefully multiple concurrent
619 opens of the same device. */
620 grub_file_close (file
);
622 mod
= grub_dl_load_core (core
, size
);
633 /* Load a module using a symbolic name. */
635 grub_dl_load (const char *name
)
639 char *grub_dl_dir
= grub_env_get ("prefix");
641 mod
= grub_dl_get (name
);
646 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "\"prefix\" is not set");
650 filename
= grub_xasprintf ("%s/%s.mod", grub_dl_dir
, name
);
654 mod
= grub_dl_load_file (filename
);
655 grub_free (filename
);
660 if (grub_strcmp (mod
->name
, name
) != 0)
661 grub_error (GRUB_ERR_BAD_MODULE
, "mismatched names");
666 /* Unload the module MOD. */
668 grub_dl_unload (grub_dl_t mod
)
670 grub_dl_dep_t dep
, depn
;
671 grub_dl_segment_t seg
, segn
;
673 if (mod
->ref_count
> 0)
679 grub_dl_remove (mod
);
680 grub_dl_unregister_symbols (mod
);
682 for (dep
= mod
->dep
; dep
; dep
= depn
)
686 grub_dl_unload (dep
->mod
);
691 for (seg
= mod
->segment
; seg
; seg
= segn
)
694 grub_free (seg
->addr
);
698 grub_free (mod
->name
);
699 #ifdef GRUB_MODULES_MACHINE_READONLY
700 grub_free (mod
->symtab
);
706 /* Unload unneeded modules. */
708 grub_dl_unload_unneeded (void)
710 /* Because grub_dl_remove modifies the list of modules, this
711 implementation is tricky. */
712 grub_dl_t p
= grub_dl_head
;
716 if (grub_dl_unload (p
))