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>
34 #include <grub/machine/machine.h>
36 /* Platforms where modules are in a readonly area of memory. */
37 #if defined(GRUB_MACHINE_QEMU)
38 #define GRUB_MODULES_MACHINE_READONLY
45 struct grub_dl_list
*next
;
48 typedef struct grub_dl_list
*grub_dl_list_t
;
50 static grub_dl_list_t grub_dl_head
;
53 grub_dl_add (grub_dl_t mod
)
57 if (grub_dl_get (mod
->name
))
58 return grub_error (GRUB_ERR_BAD_MODULE
,
59 "`%s' is already loaded", mod
->name
);
61 l
= (grub_dl_list_t
) grub_malloc (sizeof (*l
));
66 l
->next
= grub_dl_head
;
73 grub_dl_remove (grub_dl_t mod
)
77 for (p
= &grub_dl_head
, q
= *p
; q
; p
= &q
->next
, q
= *p
)
87 grub_dl_get (const char *name
)
91 for (l
= grub_dl_head
; l
; l
= l
->next
)
92 if (grub_strcmp (name
, l
->mod
->name
) == 0)
99 grub_dl_iterate (int (*hook
) (grub_dl_t mod
))
103 for (l
= grub_dl_head
; l
; l
= l
->next
)
112 struct grub_symbol
*next
;
115 grub_dl_t mod
; /* The module to which this symbol belongs. */
117 typedef struct grub_symbol
*grub_symbol_t
;
119 /* The size of the symbol table. */
120 #define GRUB_SYMTAB_SIZE 509
122 /* The symbol table (using an open-hash). */
123 static struct grub_symbol
*grub_symtab
[GRUB_SYMTAB_SIZE
];
125 /* Simple hash function. */
127 grub_symbol_hash (const char *s
)
132 key
= key
* 65599 + *s
++;
134 return (key
+ (key
>> 5)) % GRUB_SYMTAB_SIZE
;
137 /* Resolve the symbol name NAME and return the address.
138 Return NULL, if not found. */
140 grub_dl_resolve_symbol (const char *name
)
144 for (sym
= grub_symtab
[grub_symbol_hash (name
)]; sym
; sym
= sym
->next
)
145 if (grub_strcmp (sym
->name
, name
) == 0)
151 /* Register a symbol with the name NAME and the address ADDR. */
153 grub_dl_register_symbol (const char *name
, void *addr
, grub_dl_t mod
)
158 sym
= (grub_symbol_t
) grub_malloc (sizeof (*sym
));
164 sym
->name
= grub_strdup (name
);
177 k
= grub_symbol_hash (name
);
178 sym
->next
= grub_symtab
[k
];
179 grub_symtab
[k
] = sym
;
181 return GRUB_ERR_NONE
;
184 /* Unregister all the symbols defined in the module MOD. */
186 grub_dl_unregister_symbols (grub_dl_t mod
)
191 grub_fatal ("core symbols cannot be unregistered");
193 for (i
= 0; i
< GRUB_SYMTAB_SIZE
; i
++)
195 grub_symbol_t sym
, *p
, q
;
197 for (p
= &grub_symtab
[i
], sym
= *p
; sym
; sym
= q
)
203 grub_free ((void *) sym
->name
);
212 /* Return the address of a section whose index is N. */
214 grub_dl_get_section_addr (grub_dl_t mod
, unsigned n
)
216 grub_dl_segment_t seg
;
218 for (seg
= mod
->segment
; seg
; seg
= seg
->next
)
219 if (seg
->section
== n
)
225 /* Check if EHDR is a valid ELF header. */
227 grub_dl_check_header (void *ehdr
, grub_size_t size
)
231 /* Check the header size. */
232 if (size
< sizeof (Elf_Ehdr
))
233 return grub_error (GRUB_ERR_BAD_OS
, "ELF header smaller than expected");
235 /* Check the magic numbers. */
236 if (grub_arch_dl_check_header (ehdr
)
237 || e
->e_ident
[EI_MAG0
] != ELFMAG0
238 || e
->e_ident
[EI_MAG1
] != ELFMAG1
239 || e
->e_ident
[EI_MAG2
] != ELFMAG2
240 || e
->e_ident
[EI_MAG3
] != ELFMAG3
241 || e
->e_ident
[EI_VERSION
] != EV_CURRENT
242 || e
->e_version
!= EV_CURRENT
)
243 return grub_error (GRUB_ERR_BAD_OS
, "invalid arch independent ELF magic");
245 return GRUB_ERR_NONE
;
248 /* Load all segments from memory specified by E. */
250 grub_dl_load_segments (grub_dl_t mod
, const Elf_Ehdr
*e
)
255 for (i
= 0, s
= (Elf_Shdr
*)((char *) e
+ e
->e_shoff
);
257 i
++, s
= (Elf_Shdr
*)((char *) s
+ e
->e_shentsize
))
259 if (s
->sh_flags
& SHF_ALLOC
)
261 grub_dl_segment_t seg
;
263 seg
= (grub_dl_segment_t
) grub_malloc (sizeof (*seg
));
271 addr
= grub_memalign (s
->sh_addralign
, s
->sh_size
);
281 grub_memcpy (addr
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
284 grub_memset (addr
, 0, s
->sh_size
);
293 seg
->size
= s
->sh_size
;
295 seg
->next
= mod
->segment
;
300 return GRUB_ERR_NONE
;
304 grub_dl_resolve_symbols (grub_dl_t mod
, Elf_Ehdr
*e
)
310 Elf_Word size
, entsize
;
312 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
314 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
315 if (s
->sh_type
== SHT_SYMTAB
)
319 return grub_error (GRUB_ERR_BAD_MODULE
, "no symbol table");
321 #ifdef GRUB_MODULES_MACHINE_READONLY
322 mod
->symtab
= grub_malloc (s
->sh_size
);
323 memcpy (mod
->symtab
, (char *) e
+ s
->sh_offset
, s
->sh_size
);
325 mod
->symtab
= (Elf_Sym
*) ((char *) e
+ s
->sh_offset
);
329 entsize
= s
->sh_entsize
;
331 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shentsize
* s
->sh_link
);
332 str
= (char *) e
+ s
->sh_offset
;
336 i
++, sym
= (Elf_Sym
*) ((char *) sym
+ entsize
))
338 unsigned char type
= ELF_ST_TYPE (sym
->st_info
);
339 unsigned char bind
= ELF_ST_BIND (sym
->st_info
);
340 const char *name
= str
+ sym
->st_name
;
345 /* Resolve a global symbol. */
346 if (sym
->st_name
!= 0 && sym
->st_shndx
== 0)
348 sym
->st_value
= (Elf_Addr
) grub_dl_resolve_symbol (name
);
350 return grub_error (GRUB_ERR_BAD_MODULE
,
351 "the symbol `%s' not found", name
);
358 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
360 if (bind
!= STB_LOCAL
)
361 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
366 sym
->st_value
+= (Elf_Addr
) grub_dl_get_section_addr (mod
,
368 if (bind
!= STB_LOCAL
)
369 if (grub_dl_register_symbol (name
, (void *) sym
->st_value
, mod
))
372 if (grub_strcmp (name
, "grub_mod_init") == 0)
373 mod
->init
= (void (*) (grub_dl_t
)) sym
->st_value
;
374 else if (grub_strcmp (name
, "grub_mod_fini") == 0)
375 mod
->fini
= (void (*) (void)) sym
->st_value
;
379 sym
->st_value
= (Elf_Addr
) grub_dl_get_section_addr (mod
,
388 return grub_error (GRUB_ERR_BAD_MODULE
,
389 "unknown symbol type `%d'", (int) type
);
393 return GRUB_ERR_NONE
;
397 grub_dl_call_init (grub_dl_t mod
)
404 grub_dl_resolve_name (grub_dl_t mod
, Elf_Ehdr
*e
)
410 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
411 str
= (char *) e
+ s
->sh_offset
;
413 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
415 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
416 if (grub_strcmp (str
+ s
->sh_name
, ".modname") == 0)
418 mod
->name
= grub_strdup ((char *) e
+ s
->sh_offset
);
425 return grub_error (GRUB_ERR_BAD_MODULE
, "no module name found");
427 return GRUB_ERR_NONE
;
431 grub_dl_resolve_dependencies (grub_dl_t mod
, Elf_Ehdr
*e
)
437 s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
+ e
->e_shstrndx
* e
->e_shentsize
);
438 str
= (char *) e
+ s
->sh_offset
;
440 for (i
= 0, s
= (Elf_Shdr
*) ((char *) e
+ e
->e_shoff
);
442 i
++, s
= (Elf_Shdr
*) ((char *) s
+ e
->e_shentsize
))
443 if (grub_strcmp (str
+ s
->sh_name
, ".moddeps") == 0)
445 const char *name
= (char *) e
+ s
->sh_offset
;
446 const char *max
= name
+ s
->sh_size
;
448 while ((name
< max
) && (*name
))
453 m
= grub_dl_load (name
);
459 dep
= (grub_dl_dep_t
) grub_malloc (sizeof (*dep
));
464 dep
->next
= mod
->dep
;
467 name
+= grub_strlen (name
) + 1;
471 return GRUB_ERR_NONE
;
476 grub_dl_ref (grub_dl_t mod
)
480 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
481 grub_dl_ref (dep
->mod
);
483 return ++mod
->ref_count
;
487 grub_dl_unref (grub_dl_t mod
)
491 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
492 grub_dl_unref (dep
->mod
);
494 return --mod
->ref_count
;
499 grub_dl_flush_cache (grub_dl_t mod
)
501 grub_dl_segment_t seg
;
503 for (seg
= mod
->segment
; seg
; seg
= seg
->next
) {
505 grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
506 (unsigned long) seg
->size
, seg
->addr
);
507 grub_arch_sync_caches (seg
->addr
, seg
->size
);
512 /* Load a module from core memory. */
514 grub_dl_load_core (void *addr
, grub_size_t size
)
519 grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr
,
520 (unsigned long) size
);
522 if (grub_dl_check_header (e
, size
))
525 if (e
->e_type
!= ET_REL
)
527 grub_error (GRUB_ERR_BAD_MODULE
, "invalid ELF file type");
531 /* Make sure that every section is within the core. */
532 if (size
< e
->e_shoff
+ e
->e_shentsize
* e
->e_shnum
)
534 grub_error (GRUB_ERR_BAD_OS
, "ELF sections outside core");
538 mod
= (grub_dl_t
) grub_zalloc (sizeof (*mod
));
544 grub_dprintf ("modules", "relocating to %p\n", mod
);
545 if (grub_dl_resolve_name (mod
, e
)
546 || grub_dl_resolve_dependencies (mod
, e
)
547 || grub_dl_load_segments (mod
, e
)
548 || grub_dl_resolve_symbols (mod
, e
)
549 || grub_arch_dl_relocate_symbols (mod
, e
))
552 grub_dl_unload (mod
);
556 grub_dl_flush_cache (mod
);
558 grub_dprintf ("modules", "module name: %s\n", mod
->name
);
559 grub_dprintf ("modules", "init function: %p\n", mod
->init
);
560 grub_dl_call_init (mod
);
562 if (grub_dl_add (mod
))
564 grub_dl_unload (mod
);
571 /* Load a module from the file FILENAME. */
573 grub_dl_load_file (const char *filename
)
575 grub_file_t file
= NULL
;
580 file
= grub_file_open (filename
);
584 size
= grub_file_size (file
);
585 core
= grub_malloc (size
);
588 grub_file_close (file
);
592 if (grub_file_read (file
, core
, size
) != (int) size
)
594 grub_file_close (file
);
599 /* We must close this before we try to process dependencies.
600 Some disk backends do not handle gracefully multiple concurrent
601 opens of the same device. */
602 grub_file_close (file
);
604 mod
= grub_dl_load_core (core
, size
);
615 /* Load a module using a symbolic name. */
617 grub_dl_load (const char *name
)
621 char *grub_dl_dir
= grub_env_get ("prefix");
623 mod
= grub_dl_get (name
);
628 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "\"prefix\" is not set");
632 filename
= (char *) grub_malloc (grub_strlen (grub_dl_dir
) + 1
633 + grub_strlen (name
) + 4 + 1);
637 grub_sprintf (filename
, "%s/%s.mod", grub_dl_dir
, name
);
638 mod
= grub_dl_load_file (filename
);
639 grub_free (filename
);
644 if (grub_strcmp (mod
->name
, name
) != 0)
645 grub_error (GRUB_ERR_BAD_MODULE
, "mismatched names");
650 /* Unload the module MOD. */
652 grub_dl_unload (grub_dl_t mod
)
654 grub_dl_dep_t dep
, depn
;
655 grub_dl_segment_t seg
, segn
;
657 if (mod
->ref_count
> 0)
663 grub_dl_remove (mod
);
664 grub_dl_unregister_symbols (mod
);
666 for (dep
= mod
->dep
; dep
; dep
= depn
)
670 if (! grub_dl_unref (dep
->mod
))
671 grub_dl_unload (dep
->mod
);
676 for (seg
= mod
->segment
; seg
; seg
= segn
)
679 grub_free (seg
->addr
);
683 grub_free (mod
->name
);
684 #ifdef GRUB_MODULES_MACHINE_READONLY
685 grub_free (mod
->symtab
);
691 /* Unload unneeded modules. */
693 grub_dl_unload_unneeded (void)
695 /* Because grub_dl_remove modifies the list of modules, this
696 implementation is tricky. */
697 grub_dl_list_t p
= grub_dl_head
;
701 if (grub_dl_unload (p
->mod
))
711 /* Unload all modules. */
713 grub_dl_unload_all (void)
719 grub_dl_unload_unneeded ();
721 /* Force to decrement the ref count. This will purge pre-loaded
722 modules and manually inserted modules. */
723 for (p
= grub_dl_head
; p
; p
= p
->next
)