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/>.
23 #include <grub/misc.h>
26 #include <grub/types.h>
27 #include <grub/symbol.h>
28 #include <grub/file.h>
30 #include <grub/cache.h>
31 #include <grub/machine/machine.h>
33 /* Platforms where modules are in a readonly area of memory. */
34 #if defined(GRUB_MACHINE_QEMU)
35 #define GRUB_MODULES_MACHINE_READONLY
42 struct grub_dl_list
*next
;
45 typedef struct grub_dl_list
*grub_dl_list_t
;
47 static grub_dl_list_t grub_dl_head
;
50 grub_dl_add (grub_dl_t mod
)
54 if (grub_dl_get (mod
->name
))
55 return grub_error (GRUB_ERR_BAD_MODULE
,
56 "`%s' is already loaded", mod
->name
);
58 l
= (grub_dl_list_t
) grub_malloc (sizeof (*l
));
63 l
->next
= grub_dl_head
;
70 grub_dl_remove (grub_dl_t mod
)
74 for (p
= &grub_dl_head
, q
= *p
; q
; p
= &q
->next
, q
= *p
)
84 grub_dl_get (const char *name
)
88 for (l
= grub_dl_head
; l
; l
= l
->next
)
89 if (grub_strcmp (name
, l
->mod
->name
) == 0)
96 grub_dl_iterate (int (*hook
) (grub_dl_t mod
))
100 for (l
= grub_dl_head
; l
; l
= l
->next
)
109 struct grub_symbol
*next
;
112 grub_dl_t mod
; /* The module to which this symbol belongs. */
114 typedef struct grub_symbol
*grub_symbol_t
;
116 /* The size of the symbol table. */
117 #define GRUB_SYMTAB_SIZE 509
119 /* The symbol table (using an open-hash). */
120 static struct grub_symbol
*grub_symtab
[GRUB_SYMTAB_SIZE
];
122 /* Simple hash function. */
124 grub_symbol_hash (const char *s
)
129 key
= key
* 65599 + *s
++;
131 return (key
+ (key
>> 5)) % GRUB_SYMTAB_SIZE
;
134 /* Resolve the symbol name NAME and return the address.
135 Return NULL, if not found. */
137 grub_dl_resolve_symbol (const char *name
)
141 for (sym
= grub_symtab
[grub_symbol_hash (name
)]; sym
; sym
= sym
->next
)
142 if (grub_strcmp (sym
->name
, name
) == 0)
148 /* Register a symbol with the name NAME and the address ADDR. */
150 grub_dl_register_symbol (const char *name
, void *addr
, grub_dl_t mod
)
155 sym
= (grub_symbol_t
) grub_malloc (sizeof (*sym
));
161 sym
->name
= grub_strdup (name
);
174 k
= grub_symbol_hash (name
);
175 sym
->next
= grub_symtab
[k
];
176 grub_symtab
[k
] = sym
;
178 return GRUB_ERR_NONE
;
181 /* Unregister all the symbols defined in the module MOD. */
183 grub_dl_unregister_symbols (grub_dl_t mod
)
188 grub_fatal ("core symbols cannot be unregistered");
190 for (i
= 0; i
< GRUB_SYMTAB_SIZE
; i
++)
192 grub_symbol_t sym
, *p
, q
;
194 for (p
= &grub_symtab
[i
], sym
= *p
; sym
; sym
= q
)
200 grub_free ((void *) sym
->name
);
209 /* Return the address of a section whose index is N. */
211 grub_dl_get_section_addr (grub_dl_t mod
, unsigned n
)
213 grub_dl_segment_t seg
;
215 for (seg
= mod
->segment
; seg
; seg
= seg
->next
)
216 if (seg
->section
== n
)
222 /* Check if EHDR is a valid ELF header. */
224 grub_dl_check_header (void *ehdr
, grub_size_t size
)
228 /* Check the header size. */
229 if (size
< sizeof (Elf_Ehdr
))
230 return grub_error (GRUB_ERR_BAD_OS
, "ELF header smaller than expected");
232 /* Check the magic numbers. */
233 if (grub_arch_dl_check_header (ehdr
)
234 || e
->e_ident
[EI_MAG0
] != ELFMAG0
235 || e
->e_ident
[EI_MAG1
] != ELFMAG1
236 || e
->e_ident
[EI_MAG2
] != ELFMAG2
237 || e
->e_ident
[EI_MAG3
] != ELFMAG3
238 || e
->e_ident
[EI_VERSION
] != EV_CURRENT
239 || e
->e_version
!= EV_CURRENT
)
240 return grub_error (GRUB_ERR_BAD_OS
, "invalid arch independent ELF magic");
242 return GRUB_ERR_NONE
;
245 /* Load all segments from memory specified by E. */
247 grub_dl_load_segments (grub_dl_t mod
, const Elf_Ehdr
*e
)
252 for (i
= 0, s
= (Elf_Shdr
*)((char *) e
+ e
->e_shoff
);
254 i
++, s
= (Elf_Shdr
*)((char *) s
+ e
->e_shentsize
))
256 if (s
->sh_flags
& SHF_ALLOC
)
258 grub_dl_segment_t seg
;
260 seg
= (grub_dl_segment_t
) grub_malloc (sizeof (*seg
));
268 addr
= grub_memalign (s
->sh_addralign
, s
->sh_size
);
278 grub_memcpy (addr
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
281 grub_memset (addr
, 0, s
->sh_size
);
290 seg
->size
= s
->sh_size
;
292 seg
->next
= mod
->segment
;
297 return GRUB_ERR_NONE
;
301 grub_dl_resolve_symbols (grub_dl_t mod
, Elf_Ehdr
*e
)
307 Elf_Word size
, entsize
;
309 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
311 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
312 if (s
->sh_type
== SHT_SYMTAB
)
316 return grub_error (GRUB_ERR_BAD_MODULE
, "no symbol table");
318 #ifdef GRUB_MODULES_MACHINE_READONLY
319 mod
->symtab
= grub_malloc (s
->sh_size
);
320 memcpy (mod
->symtab
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
322 mod
->symtab
= (Elf_Sym
*) ((char *) e
+ s
->sh_offset
);
326 entsize
= s
->sh_entsize
;
328 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shentsize
* s
->sh_link
);
329 str
= (char *) e
+ s
->sh_offset
;
333 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ entsize
))
335 unsigned char type
= ELF_ST_TYPE (sym
->st_info
);
336 unsigned char bind
= ELF_ST_BIND (sym
->st_info
);
337 const char *name
= str
+ sym
->st_name
;
342 /* Resolve a global symbol. */
343 if (sym
->st_name
!= 0 && sym
->st_shndx
== 0)
345 sym
->st_value
= (Elf_Addr
) grub_dl_resolve_symbol (name
);
347 return grub_error (GRUB_ERR_BAD_MODULE
,
348 "the symbol `%s' not found", name
);
355 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
357 if (bind
!= STB_LOCAL
)
358 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
363 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
365 if (bind
!= STB_LOCAL
)
366 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
369 if (grub_strcmp (name
, "grub_mod_init") == 0)
370 mod
->init
= (void (*) (grub_dl_t
)) sym
->st_value
;
371 else if (grub_strcmp (name
, "grub_mod_fini") == 0)
372 mod
->fini
= (void (*) (void)) sym
->st_value
;
376 sym
->st_value
= (Elf_Addr
) grub_dl_get_section_addr (mod
,
385 return grub_error (GRUB_ERR_BAD_MODULE
,
386 "unknown symbol type `%d'", (int) type
);
390 return GRUB_ERR_NONE
;
394 grub_dl_call_init (grub_dl_t mod
)
401 grub_dl_resolve_name (grub_dl_t mod
, Elf_Ehdr
*e
)
407 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
408 str
= (char *) e
+ s
->sh_offset
;
410 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
412 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
413 if (grub_strcmp (str
+ s
->sh_name
, ".modname") == 0)
415 mod
->name
= grub_strdup ((char *) e
+ s
->sh_offset
);
422 return grub_error (GRUB_ERR_BAD_MODULE
, "no module name found");
424 return GRUB_ERR_NONE
;
428 grub_dl_resolve_dependencies (grub_dl_t mod
, Elf_Ehdr
*e
)
434 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
435 str
= (char *) e
+ s
->sh_offset
;
437 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
439 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
440 if (grub_strcmp (str
+ s
->sh_name
, ".moddeps") == 0)
442 const char *name
= (char *) e
+ s
->sh_offset
;
443 const char *max
= name
+ s
->sh_size
;
445 while ((name
< max
) && (*name
))
450 m
= grub_dl_load (name
);
456 dep
= (grub_dl_dep_t
) grub_malloc (sizeof (*dep
));
461 dep
->next
= mod
->dep
;
464 name
+= grub_strlen (name
) + 1;
468 return GRUB_ERR_NONE
;
473 grub_dl_ref (grub_dl_t mod
)
477 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
478 grub_dl_ref (dep
->mod
);
480 return ++mod
->ref_count
;
484 grub_dl_unref (grub_dl_t mod
)
488 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
489 grub_dl_unref (dep
->mod
);
491 return --mod
->ref_count
;
496 grub_dl_flush_cache (grub_dl_t mod
)
498 grub_dl_segment_t seg
;
500 for (seg
= mod
->segment
; seg
; seg
= seg
->next
) {
502 grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
503 (unsigned long) seg
->size
, seg
->addr
);
504 grub_arch_sync_caches (seg
->addr
, seg
->size
);
509 /* Load a module from core memory. */
511 grub_dl_load_core (void *addr
, grub_size_t size
)
516 grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr
,
517 (unsigned long) size
);
519 if (grub_dl_check_header (e
, size
))
522 if (e
->e_type
!= ET_REL
)
524 grub_error (GRUB_ERR_BAD_MODULE
, "invalid ELF file type");
528 /* Make sure that every section is within the core. */
529 if (size
< e
->e_shoff
+ e
->e_shentsize
* e
->e_shnum
)
531 grub_error (GRUB_ERR_BAD_OS
, "ELF sections outside core");
535 mod
= (grub_dl_t
) grub_malloc (sizeof (*mod
));
546 grub_dprintf ("modules", "relocating to %p\n", mod
);
547 if (grub_dl_resolve_name (mod
, e
)
548 || grub_dl_resolve_dependencies (mod
, e
)
549 || grub_dl_load_segments (mod
, e
)
550 || grub_dl_resolve_symbols (mod
, e
)
551 || grub_arch_dl_relocate_symbols (mod
, e
))
554 grub_dl_unload (mod
);
558 grub_dl_flush_cache (mod
);
560 grub_dprintf ("modules", "module name: %s\n", mod
->name
);
561 grub_dprintf ("modules", "init function: %p\n", mod
->init
);
562 grub_dl_call_init (mod
);
564 if (grub_dl_add (mod
))
566 grub_dl_unload (mod
);
573 /* Load a module from the file FILENAME. */
575 grub_dl_load_file (const char *filename
)
577 grub_file_t file
= NULL
;
582 file
= grub_file_open (filename
);
586 size
= grub_file_size (file
);
587 core
= grub_malloc (size
);
590 grub_file_close (file
);
594 if (grub_file_read (file
, core
, size
) != (int) size
)
596 grub_file_close (file
);
601 /* We must close this before we try to process dependencies.
602 Some disk backends do not handle gracefully multiple concurrent
603 opens of the same device. */
604 grub_file_close (file
);
606 mod
= grub_dl_load_core (core
, size
);
617 /* Load a module using a symbolic name. */
619 grub_dl_load (const char *name
)
623 char *grub_dl_dir
= grub_env_get ("prefix");
625 mod
= grub_dl_get (name
);
630 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "\"prefix\" is not set");
634 filename
= (char *) grub_malloc (grub_strlen (grub_dl_dir
) + 1
635 + grub_strlen (name
) + 4 + 1);
639 grub_sprintf (filename
, "%s/%s.mod", grub_dl_dir
, name
);
640 mod
= grub_dl_load_file (filename
);
641 grub_free (filename
);
646 if (grub_strcmp (mod
->name
, name
) != 0)
647 grub_error (GRUB_ERR_BAD_MODULE
, "mismatched names");
652 /* Unload the module MOD. */
654 grub_dl_unload (grub_dl_t mod
)
656 grub_dl_dep_t dep
, depn
;
657 grub_dl_segment_t seg
, segn
;
659 if (mod
->ref_count
> 0)
665 grub_dl_remove (mod
);
666 grub_dl_unregister_symbols (mod
);
668 for (dep
= mod
->dep
; dep
; dep
= depn
)
672 if (! grub_dl_unref (dep
->mod
))
673 grub_dl_unload (dep
->mod
);
678 for (seg
= mod
->segment
; seg
; seg
= segn
)
681 grub_free (seg
->addr
);
685 grub_free (mod
->name
);
686 #ifdef GRUB_MODULES_MACHINE_READONLY
687 grub_free (mod
->symtab
);
693 /* Unload unneeded modules. */
695 grub_dl_unload_unneeded (void)
697 /* Because grub_dl_remove modifies the list of modules, this
698 implementation is tricky. */
699 grub_dl_list_t p
= grub_dl_head
;
703 if (grub_dl_unload (p
->mod
))
713 /* Unload all modules. */
715 grub_dl_unload_all (void)
721 grub_dl_unload_unneeded ();
723 /* Force to decrement the ref count. This will purge pre-loaded
724 modules and manually inserted modules. */
725 for (p
= grub_dl_head
; p
; p
= p
->next
)