dl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /* dl.c - loadable module support */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. /* Force native word size */
  20. #define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
  21. #include <config.h>
  22. #include <grub/dl.h>
  23. #include <grub/obj.h>
  24. #include <grub/misc.h>
  25. #include <grub/mm.h>
  26. #include <grub/err.h>
  27. #include <grub/types.h>
  28. #include <grub/symbol.h>
  29. #include <grub/file.h>
  30. #include <grub/env.h>
  31. #include <grub/cache.h>
  32. GRUB_EXPORT(grub_dl_load_file);
  33. GRUB_EXPORT(grub_dl_load);
  34. GRUB_EXPORT(grub_dl_unload);
  35. #ifndef GRUB_UTIL
  36. GRUB_EXPORT(grub_dl_ref);
  37. GRUB_EXPORT(grub_dl_unref);
  38. #endif
  39. GRUB_EXPORT(grub_dl_iterate);
  40. GRUB_EXPORT(grub_dl_get);
  41. GRUB_EXPORT(grub_dl_register_symbol);
  42. /* Platforms where modules are in a readonly area of memory. */
  43. #if defined(GRUB_MACHINE_QEMU)
  44. #define GRUB_MODULES_MACHINE_READONLY
  45. #endif
  46. struct grub_dl_list
  47. {
  48. struct grub_dl_list *next;
  49. grub_dl_t mod;
  50. };
  51. typedef struct grub_dl_list *grub_dl_list_t;
  52. static grub_dl_list_t grub_dl_head;
  53. grub_err_t
  54. grub_dl_add (grub_dl_t mod)
  55. {
  56. grub_dl_list_t l;
  57. if (grub_dl_get (mod->name))
  58. return grub_error (GRUB_ERR_BAD_MODULE,
  59. "`%s' is already loaded", mod->name);
  60. l = (grub_dl_list_t) grub_malloc (sizeof (*l));
  61. if (! l)
  62. return grub_errno;
  63. l->mod = mod;
  64. l->next = grub_dl_head;
  65. grub_dl_head = l;
  66. return GRUB_ERR_NONE;
  67. }
  68. static void
  69. grub_dl_remove (grub_dl_t mod)
  70. {
  71. grub_dl_list_t *p, q;
  72. for (p = &grub_dl_head, q = *p; q; p = &q->next, q = *p)
  73. if (q->mod == mod)
  74. {
  75. *p = q->next;
  76. grub_free (q);
  77. return;
  78. }
  79. }
  80. grub_dl_t
  81. grub_dl_get (const char *name)
  82. {
  83. grub_dl_list_t l;
  84. for (l = grub_dl_head; l; l = l->next)
  85. if (grub_strcmp (name, l->mod->name) == 0)
  86. return l->mod;
  87. return 0;
  88. }
  89. void
  90. grub_dl_iterate (int (*hook) (grub_dl_t mod))
  91. {
  92. grub_dl_list_t l;
  93. for (l = grub_dl_head; l; l = l->next)
  94. if (hook (l->mod))
  95. break;
  96. }
  97. struct grub_symbol
  98. {
  99. struct grub_symbol *next;
  100. const char *name;
  101. void *addr;
  102. grub_dl_t mod; /* The module to which this symbol belongs. */
  103. };
  104. typedef struct grub_symbol *grub_symbol_t;
  105. /* The size of the symbol table. */
  106. #define GRUB_SYMTAB_SIZE 509
  107. /* The symbol table (using an open-hash). */
  108. static struct grub_symbol *grub_symtab[GRUB_SYMTAB_SIZE];
  109. /* Simple hash function. */
  110. static unsigned
  111. grub_symbol_hash (const char *s)
  112. {
  113. unsigned key = 0;
  114. while (*s)
  115. key = key * 65599 + *s++;
  116. return (key + (key >> 5)) % GRUB_SYMTAB_SIZE;
  117. }
  118. /* Resolve the symbol name NAME and return the address.
  119. Return NULL, if not found. */
  120. static void *
  121. grub_dl_resolve_symbol (const char *name)
  122. {
  123. grub_symbol_t sym;
  124. for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
  125. if (grub_strcmp (sym->name, name) == 0)
  126. return sym->addr;
  127. return 0;
  128. }
  129. /* Register a symbol with the name NAME and the address ADDR. */
  130. grub_err_t
  131. grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
  132. {
  133. grub_symbol_t sym;
  134. unsigned k;
  135. sym = (grub_symbol_t) grub_malloc (sizeof (*sym));
  136. if (! sym)
  137. return grub_errno;
  138. if (mod)
  139. {
  140. sym->name = grub_strdup (name);
  141. if (! sym->name)
  142. {
  143. grub_free (sym);
  144. return grub_errno;
  145. }
  146. }
  147. else
  148. sym->name = name;
  149. sym->addr = addr;
  150. sym->mod = mod;
  151. k = grub_symbol_hash (name);
  152. sym->next = grub_symtab[k];
  153. grub_symtab[k] = sym;
  154. return GRUB_ERR_NONE;
  155. }
  156. /* Unregister all the symbols defined in the module MOD. */
  157. static void
  158. grub_dl_unregister_symbols (grub_dl_t mod)
  159. {
  160. unsigned i;
  161. if (! mod)
  162. grub_fatal ("core symbols cannot be unregistered");
  163. for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
  164. {
  165. grub_symbol_t sym, *p, q;
  166. for (p = &grub_symtab[i], sym = *p; sym; sym = q)
  167. {
  168. q = sym->next;
  169. if (sym->mod == mod)
  170. {
  171. *p = q;
  172. grub_free ((void *) sym->name);
  173. grub_free (sym);
  174. }
  175. else
  176. p = &sym->next;
  177. }
  178. }
  179. }
  180. /* Return the address of a section whose index is N. */
  181. static void *
  182. grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
  183. {
  184. grub_dl_segment_t seg;
  185. for (seg = mod->segment; seg; seg = seg->next)
  186. if (seg->section == n)
  187. return seg->addr;
  188. return 0;
  189. }
  190. /* Load all segments from memory specified by E. */
  191. static grub_err_t
  192. grub_dl_load_segments (grub_dl_t mod, struct grub_obj_header *e)
  193. {
  194. unsigned i;
  195. struct grub_obj_segment *s;
  196. for (i = 0, s = &e->segments[0]; s->type != GRUB_OBJ_SEGMENT_END; i++, s++)
  197. {
  198. grub_dl_segment_t seg;
  199. void *addr;
  200. seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
  201. if (! seg)
  202. return grub_errno;
  203. addr = grub_memalign (s->align, s->size);
  204. if (! addr)
  205. {
  206. grub_free (seg);
  207. return grub_errno;
  208. }
  209. grub_memset (addr, 0, s->size);
  210. grub_memcpy (addr, (char *) e + s->offset,
  211. (s + 1)->offset - s->offset);
  212. seg->addr = addr;
  213. seg->size = s->size;
  214. seg->section = i;
  215. seg->next = mod->segment;
  216. mod->segment = seg;
  217. if (! i)
  218. {
  219. if (e->init_func != GRUB_OBJ_FUNC_NONE)
  220. mod->init = (void (*) (grub_dl_t)) ((char *) addr + e->init_func);
  221. if (e->fini_func != GRUB_OBJ_FUNC_NONE)
  222. mod->fini = (void (*) (void)) ((char *) addr + e->fini_func);
  223. }
  224. }
  225. return GRUB_ERR_NONE;
  226. }
  227. static grub_err_t
  228. grub_dl_resolve_symbols (grub_dl_t mod, struct grub_obj_header *e)
  229. {
  230. char *strtab;
  231. struct grub_obj_symbol *sym;
  232. struct grub_obj_reloc_extern *rel;
  233. strtab = (char *) e + e->string_table;
  234. for (sym = (struct grub_obj_symbol *) ((char *) e + e->symbol_table);
  235. sym->segment != GRUB_OBJ_SEGMENT_END; sym++)
  236. {
  237. char *addr;
  238. addr = grub_dl_get_section_addr (mod, sym->segment);
  239. addr += sym->offset;
  240. if (grub_dl_register_symbol (strtab + sym->name, addr, mod))
  241. return grub_errno;
  242. }
  243. for (rel = (struct grub_obj_reloc_extern *) ((char *) e + e->reloc_table);
  244. rel->segment != GRUB_OBJ_SEGMENT_END;)
  245. {
  246. char *addr, *symbol_addr;
  247. grub_addr_t addend;
  248. int type;
  249. addr = grub_dl_get_section_addr (mod, rel->segment);
  250. addr += rel->offset;
  251. type = rel->type;
  252. #if defined(GRUB_TARGET_USE_ADDEND)
  253. addend = rel->addend;
  254. #else
  255. addend = *((grub_addr_t *) addr);
  256. #endif
  257. if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END)
  258. {
  259. char *name;
  260. name = strtab + rel->symbol_name;
  261. symbol_addr = grub_dl_resolve_symbol (name);
  262. if (! symbol_addr)
  263. return grub_error (GRUB_ERR_BAD_MODULE,
  264. "symbol not found: `%s'", name);
  265. rel++;
  266. }
  267. else
  268. {
  269. symbol_addr = grub_dl_get_section_addr (mod, rel->symbol_segment);
  270. rel = (struct grub_obj_reloc_extern *)
  271. ((char *) rel + sizeof (struct grub_obj_reloc));
  272. }
  273. addend += (grub_addr_t) symbol_addr;
  274. if (type & GRUB_OBJ_REL_FLAG_REL)
  275. addend -= (grub_addr_t) addr;
  276. type &= GRUB_OBJ_REL_TYPE_MASK;
  277. switch (type)
  278. {
  279. case GRUB_OBJ_REL_TYPE_32:
  280. *((grub_uint32_t *) addr) = addend;
  281. break;
  282. #if GRUB_TARGET_SIZEOF_VOID_P == 8
  283. case GRUB_OBJ_REL_TYPE_64:
  284. *((grub_uint64_t *) addr) = addend;
  285. break;
  286. #endif
  287. #if defined(GRUB_TARGET_POWERPC)
  288. case GRUB_OBJ_REL_TYPE_16:
  289. *((grub_uint16_t *) addr) = addend;
  290. break;
  291. case GRUB_OBJ_REL_TYPE_16HI:
  292. *((grub_uint16_t *) addr) = addend >> 16;
  293. break;
  294. case GRUB_OBJ_REL_TYPE_16HA:
  295. *((grub_uint16_t *) addr) = (addend + 0x8000) >> 16;
  296. break;
  297. case GRUB_OBJ_REL_TYPE_24:
  298. {
  299. grub_uint32_t v;
  300. grub_int32_t a;
  301. v = *((grub_uint32_t *) addr);
  302. a = addend;
  303. if (a << 6 >> 6 != a)
  304. return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow");
  305. v = (v & 0xfc000003) | (addend & 0x3fffffc);
  306. *((grub_uint32_t *) addr) = v;
  307. break;
  308. }
  309. #endif
  310. #if defined(GRUB_TARGET_SPARC64)
  311. case GRUB_OBJ_REL_TYPE_LO10:
  312. {
  313. grub_uint32_t v;
  314. v = *((grub_uint32_t *) addr);
  315. v = (v & ~0x3ff) | (addend & 0x3ff);
  316. *((grub_uint32_t *) addr) = v;
  317. break;
  318. }
  319. case GRUB_OBJ_REL_TYPE_HI22:
  320. {
  321. grub_uint32_t v;
  322. v = *((grub_uint32_t *) addr);
  323. v = (v & ~0x3fffff) | ((addend >> 10) & 0x3fffff);
  324. *((grub_uint32_t *) addr) = v;
  325. break;
  326. }
  327. #if GRUB_TARGET_SIZEOF_VOID_P == 8
  328. case GRUB_OBJ_REL_TYPE_HM10:
  329. {
  330. grub_uint32_t v;
  331. v = *((grub_uint32_t *) addr);
  332. v = (v & ~0x3ff) | ((addend >> 32) & 0x3ff);
  333. *((grub_uint32_t *) addr) = v;
  334. break;
  335. }
  336. case GRUB_OBJ_REL_TYPE_HH22:
  337. {
  338. grub_uint32_t v;
  339. v = *((grub_uint32_t *) addr);
  340. v = (v & ~0x3fffff) | ((addend >> 42) & 0x3fffff);
  341. *((grub_uint32_t *) addr) = v;
  342. break;
  343. }
  344. #endif
  345. case GRUB_OBJ_REL_TYPE_30:
  346. {
  347. grub_uint32_t v;
  348. grub_int32_t a;
  349. v = *((grub_uint32_t *) addr);
  350. a = addend;
  351. if (a << 2 >> 2 != a)
  352. return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow");
  353. v = (v & 0xc0000000) | ((addend >> 2) & 0x3fffffff);
  354. *((grub_uint32_t *) addr) = v;
  355. break;
  356. }
  357. #endif
  358. default:
  359. return grub_error (GRUB_ERR_BAD_MODULE,
  360. "unknown reloc type %d", type);
  361. }
  362. }
  363. return GRUB_ERR_NONE;
  364. }
  365. static void
  366. grub_dl_call_init (grub_dl_t mod)
  367. {
  368. if (mod->init)
  369. (mod->init) (mod);
  370. }
  371. grub_err_t
  372. grub_dl_resolve_dependencies (grub_dl_t mod, char *name)
  373. {
  374. while (1)
  375. {
  376. grub_dl_t m;
  377. grub_dl_dep_t dep;
  378. name += grub_strlen (name) + 1;
  379. if (! *name)
  380. return GRUB_ERR_NONE;
  381. m = grub_dl_load (name);
  382. if (! m)
  383. return grub_errno;
  384. grub_dl_ref (m);
  385. dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
  386. if (! dep)
  387. return grub_errno;
  388. dep->mod = m;
  389. dep->next = mod->dep;
  390. mod->dep = dep;
  391. }
  392. }
  393. #if !GRUB_NO_MODULES
  394. int
  395. grub_dl_ref (grub_dl_t mod)
  396. {
  397. grub_dl_dep_t dep;
  398. for (dep = mod->dep; dep; dep = dep->next)
  399. grub_dl_ref (dep->mod);
  400. return ++mod->ref_count;
  401. }
  402. int
  403. grub_dl_unref (grub_dl_t mod)
  404. {
  405. grub_dl_dep_t dep;
  406. for (dep = mod->dep; dep; dep = dep->next)
  407. grub_dl_unref (dep->mod);
  408. return --mod->ref_count;
  409. }
  410. #endif
  411. static void
  412. grub_dl_flush_cache (grub_dl_t mod)
  413. {
  414. grub_dl_segment_t seg;
  415. for (seg = mod->segment; seg; seg = seg->next) {
  416. if (seg->size) {
  417. grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
  418. (unsigned long) seg->size, seg->addr);
  419. grub_arch_sync_caches (seg->addr, seg->size);
  420. }
  421. }
  422. }
  423. /* Load a module from core memory. */
  424. grub_dl_t
  425. grub_dl_load_core (void *addr, grub_size_t size)
  426. {
  427. struct grub_obj_header *e;
  428. grub_dl_t mod;
  429. char *name;
  430. grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
  431. (unsigned long) size);
  432. e = addr;
  433. if ((e->magic != GRUB_OBJ_HEADER_MAGIC) ||
  434. (e->version != GRUB_OBJ_HEADER_VERSION))
  435. {
  436. grub_error (GRUB_ERR_BAD_OS, "invalid object file");
  437. return 0;
  438. }
  439. mod = (grub_dl_t) grub_malloc (sizeof (*mod));
  440. if (! mod)
  441. return 0;
  442. name = (char *) addr + e->mod_deps;
  443. mod->name = grub_strdup (name);
  444. mod->ref_count = 1;
  445. mod->dep = 0;
  446. mod->segment = 0;
  447. mod->init = 0;
  448. mod->fini = 0;
  449. grub_dprintf ("modules", "relocating to %p\n", mod);
  450. if (grub_dl_resolve_dependencies (mod, name)
  451. || grub_dl_load_segments (mod, e)
  452. || grub_dl_resolve_symbols (mod, e))
  453. {
  454. mod->fini = 0;
  455. grub_dl_unload (mod);
  456. return 0;
  457. }
  458. grub_dl_flush_cache (mod);
  459. grub_dprintf ("modules", "module name: %s\n", mod->name);
  460. grub_dprintf ("modules", "init function: %p\n", mod->init);
  461. grub_dl_call_init (mod);
  462. if (grub_dl_add (mod))
  463. {
  464. grub_dl_unload (mod);
  465. return 0;
  466. }
  467. return mod;
  468. }
  469. /* Load a module from the file FILENAME. */
  470. grub_dl_t
  471. grub_dl_load_file (const char *filename)
  472. {
  473. grub_file_t file = NULL;
  474. grub_ssize_t size;
  475. void *core = 0;
  476. grub_dl_t mod = 0;
  477. file = grub_file_open (filename);
  478. if (! file)
  479. return 0;
  480. size = grub_file_size (file);
  481. core = grub_malloc (size);
  482. if (! core)
  483. {
  484. grub_file_close (file);
  485. return 0;
  486. }
  487. if (grub_file_read (file, core, size) != (int) size)
  488. {
  489. grub_file_close (file);
  490. grub_free (core);
  491. return 0;
  492. }
  493. /* We must close this before we try to process dependencies.
  494. Some disk backends do not handle gracefully multiple concurrent
  495. opens of the same device. */
  496. grub_file_close (file);
  497. mod = grub_dl_load_core (core, size);
  498. if (! mod)
  499. {
  500. grub_free (core);
  501. return 0;
  502. }
  503. mod->ref_count = 0;
  504. return mod;
  505. }
  506. /* Load a module using a symbolic name. */
  507. grub_dl_t
  508. grub_dl_load (const char *name)
  509. {
  510. #if GRUB_NO_MODULES
  511. (void) name;
  512. return 0;
  513. #else
  514. char *filename;
  515. grub_dl_t mod;
  516. char *grub_dl_dir = grub_env_get ("prefix");
  517. mod = grub_dl_get (name);
  518. if (mod)
  519. return mod;
  520. if (! grub_dl_dir) {
  521. grub_error (GRUB_ERR_FILE_NOT_FOUND, "\"prefix\" is not set");
  522. return 0;
  523. }
  524. filename = grub_xasprintf ("%s/%s.mod", grub_dl_dir, name);
  525. if (! filename)
  526. return 0;
  527. mod = grub_dl_load_file (filename);
  528. grub_free (filename);
  529. if (! mod)
  530. return 0;
  531. if (grub_strcmp (mod->name, name) != 0)
  532. grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
  533. return mod;
  534. #endif
  535. }
  536. /* Unload the module MOD. */
  537. int
  538. grub_dl_unload (grub_dl_t mod)
  539. {
  540. grub_dl_dep_t dep, depn;
  541. grub_dl_segment_t seg, segn;
  542. if (mod->ref_count > 0)
  543. return 0;
  544. if (mod->fini)
  545. (mod->fini) ();
  546. grub_dl_remove (mod);
  547. grub_dl_unregister_symbols (mod);
  548. for (dep = mod->dep; dep; dep = depn)
  549. {
  550. depn = dep->next;
  551. if (! grub_dl_unref (dep->mod))
  552. grub_dl_unload (dep->mod);
  553. grub_free (dep);
  554. }
  555. for (seg = mod->segment; seg; seg = segn)
  556. {
  557. segn = seg->next;
  558. grub_free (seg->addr);
  559. grub_free (seg);
  560. }
  561. grub_free (mod->name);
  562. #ifdef GRUB_MODULES_MACHINE_READONLY
  563. grub_free (mod->symtab);
  564. #endif
  565. grub_free (mod);
  566. return 1;
  567. }
  568. /* Unload unneeded modules. */
  569. void
  570. grub_dl_unload_unneeded (void)
  571. {
  572. /* Because grub_dl_remove modifies the list of modules, this
  573. implementation is tricky. */
  574. grub_dl_list_t p = grub_dl_head;
  575. while (p)
  576. {
  577. if (grub_dl_unload (p->mod))
  578. {
  579. p = grub_dl_head;
  580. continue;
  581. }
  582. p = p->next;
  583. }
  584. }
  585. /* Unload all modules. */
  586. void
  587. grub_dl_unload_all (void)
  588. {
  589. while (grub_dl_head)
  590. {
  591. grub_dl_list_t p;
  592. grub_dl_unload_unneeded ();
  593. /* Force to decrement the ref count. This will purge pre-loaded
  594. modules and manually inserted modules. */
  595. for (p = grub_dl_head; p; p = p->next)
  596. p->mod->ref_count--;
  597. }
  598. }