~psusi/ubuntu/saucy/grub2/fix-dmraid

« back to all changes in this revision

Viewing changes to .pc/no_insmod_on_sb.patch/grub-core/kern/dl.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2013-01-03 11:40:44 UTC
  • mfrom: (17.6.31 experimental)
  • Revision ID: package-import@ubuntu.com-20130103114044-et8gar9lol415wc9
Tags: 2.00-10ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme and an appropriate background for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel option.
  - Bypass menu unless other OSes are installed or Shift is pressed.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Reduce visual clutter in normal mode.
  - Remove verbose messages printed before reading configuration.
  - Suppress kernel/initrd progress messages, except in recovery mode.
  - Show the boot menu if the previous boot failed.
  - Adjust upgrade version checks for Ubuntu.
  - Suppress "GRUB loading" message unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Check hardware support before using gfxpayload=keep.
  - Set vt.handoff=7 for smooth handoff to kernel graphical mode.
  - In recovery mode, add nomodeset to the Linux kernel arguments, and
    remove the 'set gfxpayload=keep' command.
  - Skip Windows os-prober entries on Wubi systems, and suppress the menu
    by default if those are the only other-OS entries.
  - Handle probing striped DM-RAID devices.
  - Replace 'single' by 'recovery' when friendly-recovery is installed.
  - Disable cursor as early as possible in grub_main.
  - Apply patch from Fedora to add a "linuxefi" loader.
  - Automatically call linuxefi from linux when necessary.
  - On amd64, add raw-uefi custom upload tarballs for signing.
  - Generate configuration for signed UEFI kernels if available.
  - Install signed images if UEFI Secure Boot is enabled.
  - Output a menu entry for firmware setup on UEFI FastBoot systems.
  - Stop using the /usr/share/images/desktop-base/desktop-grub.png
    alternative as the fallback background.
  - If the postinst is running in a container, skip grub-install and all
    its associated questions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
20
/* Force native word size */
 
21
#define GRUB_TARGET_WORDSIZE (8 * GRUB_CPU_SIZEOF_VOID_P)
 
22
 
 
23
#include <config.h>
 
24
#include <grub/elf.h>
 
25
#include <grub/dl.h>
 
26
#include <grub/misc.h>
 
27
#include <grub/mm.h>
 
28
#include <grub/err.h>
 
29
#include <grub/types.h>
 
30
#include <grub/symbol.h>
 
31
#include <grub/file.h>
 
32
#include <grub/env.h>
 
33
#include <grub/cache.h>
 
34
#include <grub/i18n.h>
 
35
 
 
36
/* Platforms where modules are in a readonly area of memory.  */
 
37
#if defined(GRUB_MACHINE_QEMU)
 
38
#define GRUB_MODULES_MACHINE_READONLY
 
39
#endif
 
40
 
 
41
#ifdef GRUB_MACHINE_EMU
 
42
#include <sys/mman.h>
 
43
#endif
 
44
 
 
45
 
 
46
 
 
47
#pragma GCC diagnostic ignored "-Wcast-align"
 
48
 
 
49
grub_dl_t grub_dl_head = 0;
 
50
 
 
51
grub_err_t
 
52
grub_dl_add (grub_dl_t mod);
 
53
 
 
54
grub_err_t
 
55
grub_dl_add (grub_dl_t mod)
 
56
{
 
57
  if (grub_dl_get (mod->name))
 
58
    return grub_error (GRUB_ERR_BAD_MODULE,
 
59
                       "`%s' is already loaded", mod->name);
 
60
 
 
61
  mod->next = grub_dl_head;
 
62
  grub_dl_head = mod;
 
63
 
 
64
  return GRUB_ERR_NONE;
 
65
}
 
66
 
 
67
static void
 
68
grub_dl_remove (grub_dl_t mod)
 
69
{
 
70
  grub_dl_t *p, q;
 
71
 
 
72
  for (p = &grub_dl_head, q = *p; q; p = &q->next, q = *p)
 
73
    if (q == mod)
 
74
      {
 
75
        *p = q->next;
 
76
        return;
 
77
      }
 
78
}
 
79
 
 
80
grub_dl_t
 
81
grub_dl_get (const char *name)
 
82
{
 
83
  grub_dl_t l;
 
84
 
 
85
  for (l = grub_dl_head; l; l = l->next)
 
86
    if (grub_strcmp (name, l->name) == 0)
 
87
      return l;
 
88
 
 
89
  return 0;
 
90
}
 
91
 
 
92
 
 
93
 
 
94
struct grub_symbol
 
95
{
 
96
  struct grub_symbol *next;
 
97
  const char *name;
 
98
  void *addr;
 
99
  int isfunc;
 
100
  grub_dl_t mod;        /* The module to which this symbol belongs.  */
 
101
};
 
102
typedef struct grub_symbol *grub_symbol_t;
 
103
 
 
104
/* The size of the symbol table.  */
 
105
#define GRUB_SYMTAB_SIZE        509
 
106
 
 
107
/* The symbol table (using an open-hash).  */
 
108
static struct grub_symbol *grub_symtab[GRUB_SYMTAB_SIZE];
 
109
 
 
110
/* Simple hash function.  */
 
111
static unsigned
 
112
grub_symbol_hash (const char *s)
 
113
{
 
114
  unsigned key = 0;
 
115
 
 
116
  while (*s)
 
117
    key = key * 65599 + *s++;
 
118
 
 
119
  return (key + (key >> 5)) % GRUB_SYMTAB_SIZE;
 
120
}
 
121
 
 
122
/* Resolve the symbol name NAME and return the address.
 
123
   Return NULL, if not found.  */
 
124
static grub_symbol_t
 
125
grub_dl_resolve_symbol (const char *name)
 
126
{
 
127
  grub_symbol_t sym;
 
128
 
 
129
  for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
 
130
    if (grub_strcmp (sym->name, name) == 0)
 
131
      return sym;
 
132
 
 
133
  return 0;
 
134
}
 
135
 
 
136
/* Register a symbol with the name NAME and the address ADDR.  */
 
137
grub_err_t
 
138
grub_dl_register_symbol (const char *name, void *addr, int isfunc,
 
139
                         grub_dl_t mod)
 
140
{
 
141
  grub_symbol_t sym;
 
142
  unsigned k;
 
143
 
 
144
  sym = (grub_symbol_t) grub_malloc (sizeof (*sym));
 
145
  if (! sym)
 
146
    return grub_errno;
 
147
 
 
148
  if (mod)
 
149
    {
 
150
      sym->name = grub_strdup (name);
 
151
      if (! sym->name)
 
152
        {
 
153
          grub_free (sym);
 
154
          return grub_errno;
 
155
        }
 
156
    }
 
157
  else
 
158
    sym->name = name;
 
159
 
 
160
  sym->addr = addr;
 
161
  sym->mod = mod;
 
162
  sym->isfunc = isfunc;
 
163
 
 
164
  k = grub_symbol_hash (name);
 
165
  sym->next = grub_symtab[k];
 
166
  grub_symtab[k] = sym;
 
167
 
 
168
  return GRUB_ERR_NONE;
 
169
}
 
170
 
 
171
/* Unregister all the symbols defined in the module MOD.  */
 
172
static void
 
173
grub_dl_unregister_symbols (grub_dl_t mod)
 
174
{
 
175
  unsigned i;
 
176
 
 
177
  if (! mod)
 
178
    grub_fatal ("core symbols cannot be unregistered");
 
179
 
 
180
  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
 
181
    {
 
182
      grub_symbol_t sym, *p, q;
 
183
 
 
184
      for (p = &grub_symtab[i], sym = *p; sym; sym = q)
 
185
        {
 
186
          q = sym->next;
 
187
          if (sym->mod == mod)
 
188
            {
 
189
              *p = q;
 
190
              grub_free ((void *) sym->name);
 
191
              grub_free (sym);
 
192
            }
 
193
          else
 
194
            p = &sym->next;
 
195
        }
 
196
    }
 
197
}
 
198
 
 
199
/* Return the address of a section whose index is N.  */
 
200
static void *
 
201
grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
 
202
{
 
203
  grub_dl_segment_t seg;
 
204
 
 
205
  for (seg = mod->segment; seg; seg = seg->next)
 
206
    if (seg->section == n)
 
207
      return seg->addr;
 
208
 
 
209
  return 0;
 
210
}
 
211
 
 
212
/* Check if EHDR is a valid ELF header.  */
 
213
static grub_err_t
 
214
grub_dl_check_header (void *ehdr, grub_size_t size)
 
215
{
 
216
  Elf_Ehdr *e = ehdr;
 
217
  grub_err_t err;
 
218
 
 
219
  /* Check the header size.  */
 
220
  if (size < sizeof (Elf_Ehdr))
 
221
    return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected");
 
222
 
 
223
  /* Check the magic numbers.  */
 
224
  if (e->e_ident[EI_MAG0] != ELFMAG0
 
225
      || e->e_ident[EI_MAG1] != ELFMAG1
 
226
      || e->e_ident[EI_MAG2] != ELFMAG2
 
227
      || e->e_ident[EI_MAG3] != ELFMAG3
 
228
      || e->e_ident[EI_VERSION] != EV_CURRENT
 
229
      || e->e_version != EV_CURRENT)
 
230
    return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
 
231
 
 
232
  err = grub_arch_dl_check_header (ehdr);
 
233
  if (err)
 
234
    return err;
 
235
 
 
236
  return GRUB_ERR_NONE;
 
237
}
 
238
 
 
239
/* Load all segments from memory specified by E.  */
 
240
static grub_err_t
 
241
grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
 
242
{
 
243
  unsigned i;
 
244
  Elf_Shdr *s;
 
245
  grub_size_t tsize = 0, talign = 1;
 
246
#if defined (__ia64__) || defined (__powerpc__)
 
247
  grub_size_t tramp;
 
248
  grub_size_t got;
 
249
#endif
 
250
  char *ptr;
 
251
 
 
252
  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
 
253
       i < e->e_shnum;
 
254
       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
 
255
    {
 
256
      tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size;
 
257
      if (talign < s->sh_addralign)
 
258
        talign = s->sh_addralign;
 
259
    }
 
260
 
 
261
#if defined (__ia64__) || defined (__powerpc__)
 
262
  grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
 
263
  tramp *= GRUB_ARCH_DL_TRAMP_SIZE;
 
264
  got *= sizeof (grub_uint64_t);
 
265
  tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
 
266
  if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
 
267
    talign = GRUB_ARCH_DL_TRAMP_ALIGN;
 
268
  tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
 
269
  if (talign < GRUB_ARCH_DL_GOT_ALIGN)
 
270
    talign = GRUB_ARCH_DL_GOT_ALIGN;
 
271
#endif
 
272
 
 
273
#ifdef GRUB_MACHINE_EMU
 
274
  if (talign < 8192 * 16)
 
275
    talign = 8192 * 16;
 
276
  tsize = ALIGN_UP (tsize, 8192 * 16);
 
277
#endif
 
278
 
 
279
  mod->base = grub_memalign (talign, tsize);
 
280
  if (!mod->base)
 
281
    return grub_errno;
 
282
  mod->sz = tsize;
 
283
  ptr = mod->base;
 
284
 
 
285
#ifdef GRUB_MACHINE_EMU
 
286
  mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
 
287
#endif
 
288
 
 
289
  for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
 
290
       i < e->e_shnum;
 
291
       i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
 
292
    {
 
293
      if (s->sh_flags & SHF_ALLOC)
 
294
        {
 
295
          grub_dl_segment_t seg;
 
296
 
 
297
          seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
 
298
          if (! seg)
 
299
            return grub_errno;
 
300
 
 
301
          if (s->sh_size)
 
302
            {
 
303
              void *addr;
 
304
 
 
305
              ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
 
306
              addr = ptr;
 
307
              ptr += s->sh_size;
 
308
 
 
309
              switch (s->sh_type)
 
310
                {
 
311
                case SHT_PROGBITS:
 
312
                  grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
 
313
                  break;
 
314
                case SHT_NOBITS:
 
315
                  grub_memset (addr, 0, s->sh_size);
 
316
                  break;
 
317
                }
 
318
 
 
319
              seg->addr = addr;
 
320
            }
 
321
          else
 
322
            seg->addr = 0;
 
323
 
 
324
          seg->size = s->sh_size;
 
325
          seg->section = i;
 
326
          seg->next = mod->segment;
 
327
          mod->segment = seg;
 
328
        }
 
329
    }
 
330
#if defined (__ia64__) || defined (__powerpc__)
 
331
  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
 
332
  mod->tramp = ptr;
 
333
  ptr += tramp;
 
334
  ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
 
335
  mod->got = ptr;
 
336
  ptr += got;
 
337
#endif
 
338
 
 
339
  return GRUB_ERR_NONE;
 
340
}
 
341
 
 
342
static grub_err_t
 
343
grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
 
344
{
 
345
  unsigned i;
 
346
  Elf_Shdr *s;
 
347
  Elf_Sym *sym;
 
348
  const char *str;
 
349
  Elf_Word size, entsize;
 
350
 
 
351
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
 
352
       i < e->e_shnum;
 
353
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
 
354
    if (s->sh_type == SHT_SYMTAB)
 
355
      break;
 
356
 
 
357
  if (i == e->e_shnum)
 
358
    return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
 
359
 
 
360
#ifdef GRUB_MODULES_MACHINE_READONLY
 
361
  mod->symtab = grub_malloc (s->sh_size);
 
362
  memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
 
363
#else
 
364
  mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
 
365
#endif
 
366
  sym = mod->symtab;
 
367
  size = s->sh_size;
 
368
  entsize = s->sh_entsize;
 
369
 
 
370
  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
 
371
  str = (char *) e + s->sh_offset;
 
372
 
 
373
  for (i = 0;
 
374
       i < size / entsize;
 
375
       i++, sym = (Elf_Sym *) ((char *) sym + entsize))
 
376
    {
 
377
      unsigned char type = ELF_ST_TYPE (sym->st_info);
 
378
      unsigned char bind = ELF_ST_BIND (sym->st_info);
 
379
      const char *name = str + sym->st_name;
 
380
 
 
381
      switch (type)
 
382
        {
 
383
        case STT_NOTYPE:
 
384
        case STT_OBJECT:
 
385
          /* Resolve a global symbol.  */
 
386
          if (sym->st_name != 0 && sym->st_shndx == 0)
 
387
            {
 
388
              grub_symbol_t nsym = grub_dl_resolve_symbol (name);
 
389
              if (! nsym)
 
390
                return grub_error (GRUB_ERR_BAD_MODULE,
 
391
                                   N_("symbol `%s' not found"), name);
 
392
              sym->st_value = (Elf_Addr) nsym->addr;
 
393
              if (nsym->isfunc)
 
394
                sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
 
395
            }
 
396
          else
 
397
            {
 
398
              sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
 
399
                                                                    sym->st_shndx);
 
400
              if (bind != STB_LOCAL)
 
401
                if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
 
402
                  return grub_errno;
 
403
            }
 
404
          break;
 
405
 
 
406
        case STT_FUNC:
 
407
          sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
 
408
                                                                sym->st_shndx);
 
409
#ifdef __ia64__
 
410
          {
 
411
              /* FIXME: free descriptor once it's not used anymore. */
 
412
              char **desc;
 
413
              desc = grub_malloc (2 * sizeof (char *));
 
414
              if (!desc)
 
415
                return grub_errno;
 
416
              desc[0] = (void *) sym->st_value;
 
417
              desc[1] = mod->base;
 
418
              sym->st_value = (grub_addr_t) desc;
 
419
          }
 
420
#endif
 
421
          if (bind != STB_LOCAL)
 
422
            if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
 
423
              return grub_errno;
 
424
          if (grub_strcmp (name, "grub_mod_init") == 0)
 
425
            mod->init = (void (*) (grub_dl_t)) sym->st_value;
 
426
          else if (grub_strcmp (name, "grub_mod_fini") == 0)
 
427
            mod->fini = (void (*) (void)) sym->st_value;
 
428
          break;
 
429
 
 
430
        case STT_SECTION:
 
431
          sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod,
 
432
                                                               sym->st_shndx);
 
433
          break;
 
434
 
 
435
        case STT_FILE:
 
436
          sym->st_value = 0;
 
437
          break;
 
438
 
 
439
        default:
 
440
          return grub_error (GRUB_ERR_BAD_MODULE,
 
441
                             "unknown symbol type `%d'", (int) type);
 
442
        }
 
443
    }
 
444
 
 
445
  return GRUB_ERR_NONE;
 
446
}
 
447
 
 
448
static void
 
449
grub_dl_call_init (grub_dl_t mod)
 
450
{
 
451
  if (mod->init)
 
452
    (mod->init) (mod);
 
453
}
 
454
 
 
455
/* Me, Vladimir Serbinenko, hereby I add this module check as per new
 
456
   GNU module policy. Note that this license check is informative only.
 
457
   Modules have to be licensed under GPLv3 or GPLv3+ (optionally
 
458
   multi-licensed under other licences as well) independently of the
 
459
   presence of this check and solely by linking (module loading in GRUB
 
460
   constitutes linking) and GRUB core being licensed under GPLv3+.
 
461
   Be sure to understand your license obligations.
 
462
*/
 
463
static grub_err_t
 
464
grub_dl_check_license (Elf_Ehdr *e)
 
465
{
 
466
  Elf_Shdr *s;
 
467
  const char *str;
 
468
  unsigned i;
 
469
 
 
470
  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
 
471
  str = (char *) e + s->sh_offset;
 
472
 
 
473
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
 
474
       i < e->e_shnum;
 
475
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
 
476
    if (grub_strcmp (str + s->sh_name, ".module_license") == 0)
 
477
      {
 
478
        if (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
 
479
            || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
 
480
            || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)
 
481
          return GRUB_ERR_NONE;
 
482
      }
 
483
 
 
484
  return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
 
485
}
 
486
 
 
487
static grub_err_t
 
488
grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
 
489
{
 
490
  Elf_Shdr *s;
 
491
  const char *str;
 
492
  unsigned i;
 
493
 
 
494
  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
 
495
  str = (char *) e + s->sh_offset;
 
496
 
 
497
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
 
498
       i < e->e_shnum;
 
499
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
 
500
    if (grub_strcmp (str + s->sh_name, ".modname") == 0)
 
501
      {
 
502
        mod->name = grub_strdup ((char *) e + s->sh_offset);
 
503
        if (! mod->name)
 
504
          return grub_errno;
 
505
        break;
 
506
      }
 
507
 
 
508
  if (i == e->e_shnum)
 
509
    return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
 
510
 
 
511
  return GRUB_ERR_NONE;
 
512
}
 
513
 
 
514
static grub_err_t
 
515
grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
 
516
{
 
517
  Elf_Shdr *s;
 
518
  const char *str;
 
519
  unsigned i;
 
520
 
 
521
  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
 
522
  str = (char *) e + s->sh_offset;
 
523
 
 
524
  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
 
525
       i < e->e_shnum;
 
526
       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
 
527
    if (grub_strcmp (str + s->sh_name, ".moddeps") == 0)
 
528
      {
 
529
        const char *name = (char *) e + s->sh_offset;
 
530
        const char *max = name + s->sh_size;
 
531
 
 
532
        while ((name < max) && (*name))
 
533
          {
 
534
            grub_dl_t m;
 
535
            grub_dl_dep_t dep;
 
536
 
 
537
            m = grub_dl_load (name);
 
538
            if (! m)
 
539
              return grub_errno;
 
540
 
 
541
            grub_dl_ref (m);
 
542
 
 
543
            dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
 
544
            if (! dep)
 
545
              return grub_errno;
 
546
 
 
547
            dep->mod = m;
 
548
            dep->next = mod->dep;
 
549
            mod->dep = dep;
 
550
 
 
551
            name += grub_strlen (name) + 1;
 
552
          }
 
553
      }
 
554
 
 
555
  return GRUB_ERR_NONE;
 
556
}
 
557
 
 
558
int
 
559
grub_dl_ref (grub_dl_t mod)
 
560
{
 
561
  grub_dl_dep_t dep;
 
562
 
 
563
  if (!mod)
 
564
    return 0;
 
565
 
 
566
  for (dep = mod->dep; dep; dep = dep->next)
 
567
    grub_dl_ref (dep->mod);
 
568
 
 
569
  return ++mod->ref_count;
 
570
}
 
571
 
 
572
int
 
573
grub_dl_unref (grub_dl_t mod)
 
574
{
 
575
  grub_dl_dep_t dep;
 
576
 
 
577
  if (!mod)
 
578
    return 0;
 
579
 
 
580
  for (dep = mod->dep; dep; dep = dep->next)
 
581
    grub_dl_unref (dep->mod);
 
582
 
 
583
  return --mod->ref_count;
 
584
}
 
585
 
 
586
static void
 
587
grub_dl_flush_cache (grub_dl_t mod)
 
588
{
 
589
  grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
 
590
                (unsigned long) mod->sz, mod->base);
 
591
  grub_arch_sync_caches (mod->base, mod->sz);
 
592
}
 
593
 
 
594
/* Load a module from core memory.  */
 
595
grub_dl_t
 
596
grub_dl_load_core (void *addr, grub_size_t size)
 
597
{
 
598
  Elf_Ehdr *e;
 
599
  grub_dl_t mod;
 
600
 
 
601
  grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
 
602
                (unsigned long) size);
 
603
  e = addr;
 
604
  if (grub_dl_check_header (e, size))
 
605
    return 0;
 
606
 
 
607
  if (e->e_type != ET_REL)
 
608
    {
 
609
      grub_error (GRUB_ERR_BAD_MODULE, N_("this ELF file is not of the right type"));
 
610
      return 0;
 
611
    }
 
612
 
 
613
  /* Make sure that every section is within the core.  */
 
614
  if (size < e->e_shoff + e->e_shentsize * e->e_shnum)
 
615
    {
 
616
      grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
 
617
      return 0;
 
618
    }
 
619
 
 
620
  mod = (grub_dl_t) grub_zalloc (sizeof (*mod));
 
621
  if (! mod)
 
622
    return 0;
 
623
 
 
624
  mod->ref_count = 1;
 
625
 
 
626
  grub_dprintf ("modules", "relocating to %p\n", mod);
 
627
  /* Me, Vladimir Serbinenko, hereby I add this module check as per new
 
628
     GNU module policy. Note that this license check is informative only.
 
629
     Modules have to be licensed under GPLv3 or GPLv3+ (optionally
 
630
     multi-licensed under other licences as well) independently of the
 
631
     presence of this check and solely by linking (module loading in GRUB
 
632
     constitutes linking) and GRUB core being licensed under GPLv3+.
 
633
     Be sure to understand your license obligations.
 
634
  */
 
635
  if (grub_dl_check_license (e)
 
636
      || grub_dl_resolve_name (mod, e)
 
637
      || grub_dl_resolve_dependencies (mod, e)
 
638
      || grub_dl_load_segments (mod, e)
 
639
      || grub_dl_resolve_symbols (mod, e)
 
640
      || grub_arch_dl_relocate_symbols (mod, e))
 
641
    {
 
642
      mod->fini = 0;
 
643
      grub_dl_unload (mod);
 
644
      return 0;
 
645
    }
 
646
 
 
647
  grub_dl_flush_cache (mod);
 
648
 
 
649
  grub_dprintf ("modules", "module name: %s\n", mod->name);
 
650
  grub_dprintf ("modules", "init function: %p\n", mod->init);
 
651
  grub_dl_call_init (mod);
 
652
 
 
653
  if (grub_dl_add (mod))
 
654
    {
 
655
      grub_dl_unload (mod);
 
656
      return 0;
 
657
    }
 
658
 
 
659
  return mod;
 
660
}
 
661
 
 
662
/* Load a module from the file FILENAME.  */
 
663
grub_dl_t
 
664
grub_dl_load_file (const char *filename)
 
665
{
 
666
  grub_file_t file = NULL;
 
667
  grub_ssize_t size;
 
668
  void *core = 0;
 
669
  grub_dl_t mod = 0;
 
670
 
 
671
  file = grub_file_open (filename);
 
672
  if (! file)
 
673
    return 0;
 
674
 
 
675
  size = grub_file_size (file);
 
676
  core = grub_malloc (size);
 
677
  if (! core)
 
678
    {
 
679
      grub_file_close (file);
 
680
      return 0;
 
681
    }
 
682
 
 
683
  if (grub_file_read (file, core, size) != (int) size)
 
684
    {
 
685
      grub_file_close (file);
 
686
      grub_free (core);
 
687
      return 0;
 
688
    }
 
689
 
 
690
  /* We must close this before we try to process dependencies.
 
691
     Some disk backends do not handle gracefully multiple concurrent
 
692
     opens of the same device.  */
 
693
  grub_file_close (file);
 
694
 
 
695
  mod = grub_dl_load_core (core, size);
 
696
  grub_free (core);
 
697
  if (! mod)
 
698
    return 0;
 
699
 
 
700
  mod->ref_count--;
 
701
  return mod;
 
702
}
 
703
 
 
704
/* Load a module using a symbolic name.  */
 
705
grub_dl_t
 
706
grub_dl_load (const char *name)
 
707
{
 
708
  char *filename;
 
709
  grub_dl_t mod;
 
710
  const char *grub_dl_dir = grub_env_get ("prefix");
 
711
 
 
712
  mod = grub_dl_get (name);
 
713
  if (mod)
 
714
    return mod;
 
715
 
 
716
  if (! grub_dl_dir) {
 
717
    grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
 
718
    return 0;
 
719
  }
 
720
 
 
721
  filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod",
 
722
                             grub_dl_dir, name);
 
723
  if (! filename)
 
724
    return 0;
 
725
 
 
726
  mod = grub_dl_load_file (filename);
 
727
  grub_free (filename);
 
728
 
 
729
  if (! mod)
 
730
    return 0;
 
731
 
 
732
  if (grub_strcmp (mod->name, name) != 0)
 
733
    grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
 
734
 
 
735
  return mod;
 
736
}
 
737
 
 
738
/* Unload the module MOD.  */
 
739
int
 
740
grub_dl_unload (grub_dl_t mod)
 
741
{
 
742
  grub_dl_dep_t dep, depn;
 
743
 
 
744
  if (mod->ref_count > 0)
 
745
    return 0;
 
746
 
 
747
  if (mod->fini)
 
748
    (mod->fini) ();
 
749
 
 
750
  grub_dl_remove (mod);
 
751
  grub_dl_unregister_symbols (mod);
 
752
 
 
753
  for (dep = mod->dep; dep; dep = depn)
 
754
    {
 
755
      depn = dep->next;
 
756
 
 
757
      grub_dl_unload (dep->mod);
 
758
 
 
759
      grub_free (dep);
 
760
    }
 
761
 
 
762
  grub_free (mod->base);
 
763
  grub_free (mod->name);
 
764
#ifdef GRUB_MODULES_MACHINE_READONLY
 
765
  grub_free (mod->symtab);
 
766
#endif
 
767
  grub_free (mod);
 
768
  return 1;
 
769
}
 
770
 
 
771
/* Unload unneeded modules.  */
 
772
void
 
773
grub_dl_unload_unneeded (void)
 
774
{
 
775
  /* Because grub_dl_remove modifies the list of modules, this
 
776
     implementation is tricky.  */
 
777
  grub_dl_t p = grub_dl_head;
 
778
 
 
779
  while (p)
 
780
    {
 
781
      if (grub_dl_unload (p))
 
782
        {
 
783
          p = grub_dl_head;
 
784
          continue;
 
785
        }
 
786
 
 
787
      p = p->next;
 
788
    }
 
789
}