~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/loader/i386/bsd.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2008,2009,2010  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/loader.h>
 
20
#include <grub/i386/bsd.h>
 
21
#include <grub/i386/cpuid.h>
 
22
#include <grub/memory.h>
 
23
#include <grub/i386/memory.h>
 
24
#include <grub/file.h>
 
25
#include <grub/err.h>
 
26
#include <grub/dl.h>
 
27
#include <grub/mm.h>
 
28
#include <grub/elfload.h>
 
29
#include <grub/env.h>
 
30
#include <grub/misc.h>
 
31
#include <grub/aout.h>
 
32
#include <grub/command.h>
 
33
#include <grub/extcmd.h>
 
34
#include <grub/i18n.h>
 
35
#include <grub/ns8250.h>
 
36
 
 
37
#include <grub/video.h>
 
38
#ifdef GRUB_MACHINE_PCBIOS
 
39
#include <grub/machine/biosnum.h>
 
40
#endif
 
41
#ifdef GRUB_MACHINE_EFI
 
42
#include <grub/efi/efi.h>
 
43
#define NETBSD_DEFAULT_VIDEO_MODE "800x600"
 
44
#else
 
45
#define NETBSD_DEFAULT_VIDEO_MODE "text"
 
46
#include <grub/i386/pc/vbe.h>
 
47
#endif
 
48
#include <grub/video.h>
 
49
 
 
50
#include <grub/disk.h>
 
51
#include <grub/device.h>
 
52
#include <grub/partition.h>
 
53
#include <grub/relocator.h>
 
54
#include <grub/i386/relocator.h>
 
55
 
 
56
#define ALIGN_DWORD(a)  ALIGN_UP (a, 4)
 
57
#define ALIGN_QWORD(a)  ALIGN_UP (a, 8)
 
58
#define ALIGN_VAR(a)    ((is_64bit) ? (ALIGN_QWORD(a)) : (ALIGN_DWORD(a)))
 
59
#define ALIGN_PAGE(a)   ALIGN_UP (a, 4096)
 
60
 
 
61
static int kernel_type = KERNEL_TYPE_NONE;
 
62
static grub_dl_t my_mod;
 
63
static grub_addr_t entry, entry_hi, kern_start, kern_end;
 
64
static void *kern_chunk_src;
 
65
static grub_uint32_t bootflags;
 
66
static int is_elf_kernel, is_64bit;
 
67
static grub_uint32_t openbsd_root;
 
68
struct grub_relocator *relocator = NULL;
 
69
static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk;
 
70
 
 
71
struct bsd_tag
 
72
{
 
73
  struct bsd_tag *next;
 
74
  grub_size_t len;
 
75
  grub_uint32_t type;
 
76
  union {
 
77
    grub_uint8_t a;
 
78
    grub_uint16_t b;
 
79
    grub_uint32_t c;
 
80
  } data[0];
 
81
};
 
82
 
 
83
static struct bsd_tag *tags, *tags_last;
 
84
 
 
85
struct netbsd_module
 
86
{
 
87
  struct netbsd_module *next;
 
88
  struct grub_netbsd_btinfo_module mod;
 
89
};
 
90
 
 
91
static struct netbsd_module *netbsd_mods, *netbsd_mods_last;
 
92
 
 
93
static const struct grub_arg_option freebsd_opts[] =
 
94
  {
 
95
    {"dual", 'D', 0, N_("Display output on all consoles."), 0, 0},
 
96
    {"serial", 'h', 0, N_("Use serial console."), 0, 0},
 
97
    {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0},
 
98
    {"cdrom", 'C', 0, N_("Use CDROM as root."), 0, 0},
 
99
    {"config", 'c', 0, N_("Invoke user configuration routing."), 0, 0},
 
100
    {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0},
 
101
    {"gdb", 'g', 0, N_("Use GDB remote debugger instead of DDB."), 0, 0},
 
102
    {"mute", 'm', 0, N_("Disable all boot output."), 0, 0},
 
103
    {"nointr", 'n', 0, "", 0, 0},
 
104
    {"pause", 'p', 0, N_("Wait for keypress after every line of output."), 0, 0},
 
105
    {"quiet", 'q', 0, "", 0, 0},
 
106
    {"dfltroot", 'r', 0, N_("Use compiled-in rootdev."), 0, 0},
 
107
    {"single", 's', 0, N_("Boot into single mode."), 0, 0},
 
108
    {"verbose", 'v', 0, N_("Boot with verbose messages."), 0, 0},
 
109
    {0, 0, 0, 0, 0, 0}
 
110
  };
 
111
 
 
112
static const grub_uint32_t freebsd_flags[] =
 
113
{
 
114
  FREEBSD_RB_DUAL, FREEBSD_RB_SERIAL, FREEBSD_RB_ASKNAME,
 
115
  FREEBSD_RB_CDROM, FREEBSD_RB_CONFIG, FREEBSD_RB_KDB,
 
116
  FREEBSD_RB_GDB, FREEBSD_RB_MUTE, FREEBSD_RB_NOINTR,
 
117
  FREEBSD_RB_PAUSE, FREEBSD_RB_QUIET, FREEBSD_RB_DFLTROOT,
 
118
  FREEBSD_RB_SINGLE, FREEBSD_RB_VERBOSE, 0
 
119
};
 
120
 
 
121
static const struct grub_arg_option openbsd_opts[] =
 
122
  {
 
123
    {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0},
 
124
    {"halt", 'b', 0, N_("Don't reboot, just halt."), 0, 0},
 
125
    {"config", 'c', 0, N_("Change configured devices."), 0, 0},
 
126
    {"single", 's', 0, N_("Boot into single mode."), 0, 0},
 
127
    {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0},
 
128
    {"root", 'r', 0, N_("Set root device."), "wdXY", ARG_TYPE_STRING},
 
129
    {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, 
 
130
     N_("Use serial console."), N_("comUNIT[,SPEED]"), ARG_TYPE_STRING},
 
131
    {0, 0, 0, 0, 0, 0}
 
132
  };
 
133
 
 
134
static const grub_uint32_t openbsd_flags[] =
 
135
{
 
136
  OPENBSD_RB_ASKNAME, OPENBSD_RB_HALT, OPENBSD_RB_CONFIG,
 
137
  OPENBSD_RB_SINGLE, OPENBSD_RB_KDB, 0
 
138
};
 
139
 
 
140
#define OPENBSD_ROOT_ARG (ARRAY_SIZE (openbsd_flags) - 1)
 
141
#define OPENBSD_SERIAL_ARG (ARRAY_SIZE (openbsd_flags))
 
142
 
 
143
static const struct grub_arg_option netbsd_opts[] =
 
144
  {
 
145
    {"no-smp", '1', 0, N_("Disable SMP."), 0, 0},
 
146
    {"no-acpi", '2', 0, N_("Disable ACPI."), 0, 0},
 
147
    {"askname", 'a', 0, N_("Ask for file name to reboot from."), 0, 0},
 
148
    {"halt", 'b', 0, N_("Don't reboot, just halt."), 0, 0},
 
149
    {"config", 'c', 0, N_("Change configured devices."), 0, 0},
 
150
    {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0},
 
151
    {"miniroot", 'm', 0, "", 0, 0},
 
152
    {"quiet", 'q', 0, N_("Don't display boot diagnostic messages."), 0, 0},
 
153
    {"single", 's', 0, N_("Boot into single mode."), 0, 0},
 
154
    {"verbose", 'v', 0, N_("Boot with verbose messages."), 0, 0},
 
155
    {"debug", 'x', 0, N_("Boot with debug messages."), 0, 0},
 
156
    {"silent", 'z', 0, N_("Supress normal output (warnings remain)."), 0, 0},
 
157
    {"root", 'r', 0, N_("Set root device."), N_("DEVICE"), ARG_TYPE_STRING},
 
158
    {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, 
 
159
     N_("Use serial console."), N_("[ADDR|comUNIT][,SPEED]"), ARG_TYPE_STRING},
 
160
    {0, 0, 0, 0, 0, 0}
 
161
  };
 
162
 
 
163
static const grub_uint32_t netbsd_flags[] =
 
164
{
 
165
  NETBSD_AB_NOSMP, NETBSD_AB_NOACPI, NETBSD_RB_ASKNAME,
 
166
  NETBSD_RB_HALT, NETBSD_RB_USERCONFIG, NETBSD_RB_KDB,
 
167
  NETBSD_RB_MINIROOT, NETBSD_AB_QUIET, NETBSD_RB_SINGLE,
 
168
  NETBSD_AB_VERBOSE, NETBSD_AB_DEBUG, NETBSD_AB_SILENT, 0
 
169
};
 
170
 
 
171
#define NETBSD_ROOT_ARG (ARRAY_SIZE (netbsd_flags) - 1)
 
172
#define NETBSD_SERIAL_ARG (ARRAY_SIZE (netbsd_flags))
 
173
 
 
174
static void
 
175
grub_bsd_get_device (grub_uint32_t * biosdev,
 
176
                     grub_uint32_t * unit,
 
177
                     grub_uint32_t * slice, grub_uint32_t * part)
 
178
{
 
179
  grub_device_t dev;
 
180
 
 
181
#ifdef GRUB_MACHINE_PCBIOS
 
182
  *biosdev = grub_get_root_biosnumber () & 0xff;
 
183
#else
 
184
  *biosdev = 0xff;
 
185
#endif
 
186
  *unit = (*biosdev & 0x7f);
 
187
  *slice = 0xff;
 
188
  *part = 0xff;
 
189
  dev = grub_device_open (0);
 
190
  if (dev && dev->disk && dev->disk->partition)
 
191
    {
 
192
      if (dev->disk->partition->parent)
 
193
        {
 
194
          *part = dev->disk->partition->number;
 
195
          *slice = dev->disk->partition->parent->number + 1;
 
196
        }
 
197
      else
 
198
        *slice = dev->disk->partition->number + 1;
 
199
    }
 
200
  if (dev)
 
201
    grub_device_close (dev);
 
202
}
 
203
 
 
204
grub_err_t
 
205
grub_bsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len)
 
206
{
 
207
  struct bsd_tag *newtag;
 
208
 
 
209
  newtag = grub_malloc (len + sizeof (struct bsd_tag));
 
210
  if (!newtag)
 
211
    return grub_errno;
 
212
  newtag->len = len;
 
213
  newtag->type = type;
 
214
  newtag->next = NULL;
 
215
  if (len)
 
216
    grub_memcpy (newtag->data, data, len);
 
217
 
 
218
  if (kernel_type == KERNEL_TYPE_FREEBSD 
 
219
      && type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP))
 
220
    {
 
221
      struct bsd_tag *p;
 
222
      for (p = tags;
 
223
           p->type != (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND);
 
224
           p = p->next);
 
225
 
 
226
      if (p)
 
227
        {
 
228
          newtag->next = p->next;
 
229
          p->next = newtag;
 
230
          if (newtag->next == NULL)
 
231
            tags_last = newtag;
 
232
          return GRUB_ERR_NONE;
 
233
        }
 
234
    }
 
235
 
 
236
  if (tags_last)
 
237
    tags_last->next = newtag;
 
238
  else
 
239
    tags = newtag;
 
240
  tags_last = newtag;
 
241
 
 
242
  return GRUB_ERR_NONE;
 
243
}
 
244
 
 
245
struct grub_e820_mmap
 
246
{
 
247
  grub_uint64_t addr;
 
248
  grub_uint64_t size;
 
249
  grub_uint32_t type;
 
250
} __attribute__((packed));
 
251
#define GRUB_E820_RAM        1
 
252
#define GRUB_E820_RESERVED   2
 
253
#define GRUB_E820_ACPI       3
 
254
#define GRUB_E820_NVS        4
 
255
#define GRUB_E820_EXEC_CODE  5
 
256
 
 
257
static void
 
258
generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf)
 
259
{
 
260
  int count = 0;
 
261
  struct grub_e820_mmap *mmap = buf;
 
262
  struct grub_e820_mmap prev, cur;
 
263
 
 
264
  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
 
265
                                  grub_memory_type_t);
 
266
  int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size,
 
267
                             grub_memory_type_t type)
 
268
    {
 
269
      cur.addr = addr;
 
270
      cur.size = size;
 
271
      switch (type)
 
272
        {
 
273
        case GRUB_MEMORY_AVAILABLE:
 
274
          cur.type = GRUB_E820_RAM;
 
275
          break;
 
276
 
 
277
        case GRUB_MEMORY_ACPI:
 
278
          cur.type = GRUB_E820_ACPI;
 
279
          break;
 
280
 
 
281
        case GRUB_MEMORY_NVS:
 
282
          cur.type = GRUB_E820_NVS;
 
283
          break;
 
284
 
 
285
        default:
 
286
        case GRUB_MEMORY_CODE:
 
287
        case GRUB_MEMORY_RESERVED:
 
288
          cur.type = GRUB_E820_RESERVED;
 
289
          break;
 
290
        }
 
291
 
 
292
      /* Merge regions if possible. */
 
293
      if (count && cur.type == prev.type && cur.addr == prev.addr + prev.size)
 
294
        {
 
295
          prev.size += cur.size;
 
296
          if (mmap)
 
297
            mmap[-1] = prev;
 
298
        }
 
299
      else
 
300
        {
 
301
          if (mmap)
 
302
            *mmap++ = cur;
 
303
          prev = cur;
 
304
          count++;
 
305
        }
 
306
 
 
307
      if (kernel_type == KERNEL_TYPE_OPENBSD && prev.addr < 0x100000
 
308
          && prev.addr + prev.size > 0x100000)
 
309
        {
 
310
          cur.addr = 0x100000;
 
311
          cur.size = prev.addr + prev.size - 0x100000;
 
312
          cur.type = prev.type;
 
313
          prev.size = 0x100000 - prev.addr;
 
314
          if (mmap)
 
315
            {
 
316
              mmap[-1] = prev;
 
317
              mmap[0] = cur;
 
318
              mmap++;
 
319
            }
 
320
          prev = cur;
 
321
          count++;
 
322
        }
 
323
 
 
324
      return 0;
 
325
    }
 
326
 
 
327
  grub_mmap_iterate (hook);
 
328
 
 
329
  if (len)
 
330
    *len = count * sizeof (struct grub_e820_mmap);
 
331
  *cnt = count;
 
332
 
 
333
  return;
 
334
}
 
335
 
 
336
static grub_err_t
 
337
grub_bsd_add_mmap (void)
 
338
{
 
339
  grub_size_t len, cnt;
 
340
  void *buf = NULL, *buf0;
 
341
 
 
342
  generate_e820_mmap (&len, &cnt, buf);
 
343
 
 
344
  if (kernel_type == KERNEL_TYPE_NETBSD)
 
345
    len += sizeof (grub_uint32_t);
 
346
 
 
347
  if (kernel_type == KERNEL_TYPE_OPENBSD)
 
348
    len += sizeof (struct grub_e820_mmap);
 
349
 
 
350
  buf = grub_malloc (len);
 
351
  if (!buf)
 
352
    return grub_errno;
 
353
 
 
354
  buf0 = buf;
 
355
  if (kernel_type == KERNEL_TYPE_NETBSD)
 
356
    {
 
357
      *(grub_uint32_t *) buf = cnt;
 
358
      buf = ((grub_uint32_t *) buf + 1);
 
359
    }
 
360
 
 
361
  generate_e820_mmap (NULL, &cnt, buf);
 
362
 
 
363
  if (kernel_type == KERNEL_TYPE_OPENBSD)
 
364
    grub_memset ((grub_uint8_t *) buf + len - sizeof (struct grub_e820_mmap), 0,
 
365
                 sizeof (struct grub_e820_mmap));
 
366
 
 
367
  grub_dprintf ("bsd", "%u entries in smap\n", (unsigned) cnt);
 
368
  if (kernel_type == KERNEL_TYPE_NETBSD)
 
369
    grub_bsd_add_meta (NETBSD_BTINFO_MEMMAP, buf0, len);
 
370
  else if (kernel_type == KERNEL_TYPE_OPENBSD)
 
371
    grub_bsd_add_meta (OPENBSD_BOOTARG_MMAP, buf0, len);
 
372
  else
 
373
    grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
 
374
                       FREEBSD_MODINFOMD_SMAP, buf0, len);
 
375
 
 
376
  grub_free (buf0);
 
377
 
 
378
  return grub_errno;
 
379
}
 
380
 
 
381
grub_err_t
 
382
grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv,
 
383
                              grub_addr_t addr, grub_uint32_t size)
 
384
{
 
385
  char *name;
 
386
  name = grub_strrchr (filename, '/');
 
387
  if (name)
 
388
    name++;
 
389
  else
 
390
    name = filename;
 
391
  if (grub_strcmp (type, "/boot/zfs/zpool.cache") == 0)
 
392
    name = "/boot/zfs/zpool.cache";
 
393
 
 
394
  if (grub_bsd_add_meta (FREEBSD_MODINFO_NAME, name, grub_strlen (name) + 1))
 
395
    return grub_errno;
 
396
 
 
397
  if (is_64bit)
 
398
    {
 
399
      grub_uint64_t addr64 = addr, size64 = size;
 
400
      if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1)
 
401
          || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, sizeof (addr64)) 
 
402
          || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, sizeof (size64)))
 
403
        return grub_errno;
 
404
    }
 
405
  else
 
406
    {
 
407
      if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1)
 
408
          || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, sizeof (addr))
 
409
          || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size, sizeof (size)))
 
410
        return grub_errno;
 
411
    }
 
412
 
 
413
  if (argc)
 
414
    {
 
415
      int i, n;
 
416
 
 
417
      n = 0;
 
418
      for (i = 0; i < argc; i++)
 
419
        {
 
420
          n += grub_strlen (argv[i]) + 1;
 
421
        }
 
422
 
 
423
      if (n)
 
424
        {
 
425
          char cmdline[n], *p;
 
426
 
 
427
          p = cmdline;
 
428
          for (i = 0; i < argc; i++)
 
429
            {
 
430
              grub_strcpy (p, argv[i]);
 
431
              p += grub_strlen (argv[i]);
 
432
              *(p++) = ' ';
 
433
            }
 
434
          *p = 0;
 
435
 
 
436
          if (grub_bsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n))
 
437
            return grub_errno;
 
438
        }
 
439
    }
 
440
 
 
441
  return GRUB_ERR_NONE;
 
442
}
 
443
 
 
444
static void
 
445
grub_freebsd_list_modules (void)
 
446
{
 
447
  struct bsd_tag *tag;
 
448
 
 
449
  grub_printf ("  %-18s  %-18s%14s%14s\n", "name", "type", "addr", "size");
 
450
 
 
451
  for (tag = tags; tag; tag = tag->next)
 
452
    {
 
453
      switch (tag->type)
 
454
        {
 
455
        case FREEBSD_MODINFO_NAME:
 
456
        case FREEBSD_MODINFO_TYPE:
 
457
          grub_printf ("  %-18s", (char *) tag->data);
 
458
          break;
 
459
        case FREEBSD_MODINFO_ADDR:
 
460
          {
 
461
            grub_uint32_t addr;
 
462
 
 
463
            addr = *((grub_uint32_t *) tag->data);
 
464
            grub_printf ("    0x%08x", addr);
 
465
            break;
 
466
          }
 
467
        case FREEBSD_MODINFO_SIZE:
 
468
          {
 
469
            grub_uint32_t len;
 
470
 
 
471
            len = *((grub_uint32_t *) tag->data);
 
472
            grub_printf ("    0x%08x\n", len);
 
473
          }
 
474
        }
 
475
    }
 
476
}
 
477
 
 
478
static grub_err_t
 
479
grub_netbsd_add_meta_module (char *filename, grub_uint32_t type,
 
480
                             grub_addr_t addr, grub_uint32_t size)
 
481
{
 
482
  char *name;
 
483
  struct netbsd_module *mod;
 
484
  name = grub_strrchr (filename, '/');
 
485
 
 
486
  if (name)
 
487
    name++;
 
488
  else
 
489
    name = filename;
 
490
 
 
491
  mod = grub_zalloc (sizeof (*mod));
 
492
  if (!mod)
 
493
    return grub_errno;
 
494
 
 
495
  grub_strncpy (mod->mod.name, name, sizeof (mod->mod.name) - 1);
 
496
  mod->mod.addr = addr;
 
497
  mod->mod.type = type;
 
498
  mod->mod.size = size;
 
499
 
 
500
  if (netbsd_mods_last)
 
501
    netbsd_mods_last->next = mod;
 
502
  else
 
503
    netbsd_mods = mod;
 
504
  netbsd_mods_last = mod;
 
505
 
 
506
  return GRUB_ERR_NONE;
 
507
}
 
508
 
 
509
static void
 
510
grub_netbsd_list_modules (void)
 
511
{
 
512
  struct netbsd_module *mod;
 
513
 
 
514
  grub_printf ("  %-18s%14s%14s%14s\n", "name", "type", "addr", "size");
 
515
 
 
516
  for (mod = netbsd_mods; mod; mod = mod->next)
 
517
    grub_printf ("  %-18s  0x%08x  0x%08x  0x%08x", mod->mod.name,
 
518
                 mod->mod.type, mod->mod.addr, mod->mod.size);
 
519
}
 
520
 
 
521
/* This function would be here but it's under different license. */
 
522
#include "bsd_pagetable.c"
 
523
 
 
524
static grub_err_t
 
525
grub_freebsd_boot (void)
 
526
{
 
527
  struct grub_freebsd_bootinfo bi;
 
528
  grub_uint8_t *p, *p0;
 
529
  grub_addr_t p_target;
 
530
  grub_size_t p_size = 0;
 
531
  grub_uint32_t bootdev, biosdev, unit, slice, part;
 
532
  grub_err_t err;
 
533
  grub_size_t tag_buf_len = 0;
 
534
 
 
535
  auto int iterate_env (struct grub_env_var *var);
 
536
  int iterate_env (struct grub_env_var *var)
 
537
  {
 
538
    if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1]))
 
539
      {
 
540
        grub_strcpy ((char *) p, &var->name[sizeof("kFreeBSD.") - 1]);
 
541
        p += grub_strlen ((char *) p);
 
542
        *(p++) = '=';
 
543
        grub_strcpy ((char *) p, var->value);
 
544
        p += grub_strlen ((char *) p) + 1;
 
545
      }
 
546
 
 
547
    return 0;
 
548
  }
 
549
 
 
550
  auto int iterate_env_count (struct grub_env_var *var);
 
551
  int iterate_env_count (struct grub_env_var *var)
 
552
  {
 
553
    if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1]))
 
554
      {
 
555
        p_size += grub_strlen (&var->name[sizeof("kFreeBSD.") - 1]);
 
556
        p_size++;
 
557
        p_size += grub_strlen (var->value) + 1;
 
558
      }
 
559
 
 
560
    return 0;
 
561
  }
 
562
 
 
563
  grub_memset (&bi, 0, sizeof (bi));
 
564
  bi.version = FREEBSD_BOOTINFO_VERSION;
 
565
  bi.length = sizeof (bi);
 
566
 
 
567
  grub_bsd_get_device (&biosdev, &unit, &slice, &part);
 
568
  bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) +
 
569
             (unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT));
 
570
 
 
571
  bi.boot_device = biosdev;
 
572
 
 
573
  p_size = 0;
 
574
  grub_env_iterate (iterate_env_count);
 
575
 
 
576
  if (p_size)
 
577
    p_size = ALIGN_PAGE (kern_end + p_size + 1) - kern_end;
 
578
 
 
579
  if (is_elf_kernel)
 
580
    {
 
581
      struct bsd_tag *tag;
 
582
 
 
583
      err = grub_bsd_add_mmap ();
 
584
      if (err)
 
585
        return err;
 
586
 
 
587
      err = grub_bsd_add_meta (FREEBSD_MODINFO_END, 0, 0);
 
588
      if (err)
 
589
        return err;
 
590
      
 
591
      tag_buf_len = 0;
 
592
      for (tag = tags; tag; tag = tag->next)
 
593
        tag_buf_len = ALIGN_VAR (tag_buf_len
 
594
                                 + sizeof (struct freebsd_tag_header)
 
595
                                 + tag->len);
 
596
      p_size = ALIGN_PAGE (kern_end + p_size + tag_buf_len) - kern_end;
 
597
    }
 
598
 
 
599
  if (is_64bit)
 
600
    p_size += 4096 * 3;
 
601
 
 
602
  {
 
603
    grub_relocator_chunk_t ch;
 
604
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
605
                                           kern_end, p_size);
 
606
    if (err)
 
607
      return err;
 
608
    p = get_virtual_current_address (ch);
 
609
  }
 
610
  p_target = kern_end;
 
611
  p0 = p;
 
612
  kern_end += p_size;
 
613
 
 
614
  grub_env_iterate (iterate_env);
 
615
 
 
616
  if (p != p0)
 
617
    {
 
618
      *(p++) = 0;
 
619
 
 
620
      bi.environment = p_target;
 
621
    }
 
622
 
 
623
  if (is_elf_kernel)
 
624
    {
 
625
      grub_uint8_t *p_tag = p;
 
626
      struct bsd_tag *tag;
 
627
      
 
628
      for (tag = tags; tag; tag = tag->next)
 
629
        {
 
630
          struct freebsd_tag_header *head
 
631
            = (struct freebsd_tag_header *) p_tag;
 
632
          head->type = tag->type;
 
633
          head->len = tag->len;
 
634
          p_tag += sizeof (struct freebsd_tag_header);
 
635
          switch (tag->type)
 
636
            {
 
637
            case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_HOWTO:
 
638
              if (is_64bit)
 
639
                *(grub_uint64_t *) p_tag = bootflags;
 
640
              else
 
641
                *(grub_uint32_t *) p_tag = bootflags;
 
642
              break;
 
643
 
 
644
            case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP:
 
645
              if (is_64bit)
 
646
                *(grub_uint64_t *) p_tag = bi.environment;
 
647
              else
 
648
                *(grub_uint32_t *) p_tag = bi.environment;
 
649
              break;
 
650
 
 
651
            case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND:
 
652
              if (is_64bit)
 
653
                *(grub_uint64_t *) p_tag = kern_end;
 
654
              else
 
655
                *(grub_uint32_t *) p_tag = kern_end;
 
656
              break;
 
657
 
 
658
            default:
 
659
              grub_memcpy (p_tag, tag->data, tag->len);
 
660
              break;
 
661
            }
 
662
          p_tag += tag->len;
 
663
          p_tag = ALIGN_VAR (p_tag - p) + p;
 
664
        }
 
665
 
 
666
      bi.tags = (p - p0) + p_target;
 
667
 
 
668
      p = (ALIGN_PAGE ((p_tag - p0) + p_target) - p_target) + p0;
 
669
    }
 
670
 
 
671
  bi.kern_end = kern_end;
 
672
 
 
673
  grub_video_set_mode ("text", 0, 0);
 
674
 
 
675
  if (is_64bit)
 
676
    {
 
677
      struct grub_relocator64_state state;
 
678
      grub_uint8_t *pagetable;
 
679
      grub_uint32_t *stack;
 
680
      grub_addr_t stack_target;
 
681
 
 
682
      {
 
683
        grub_relocator_chunk_t ch;
 
684
        err = grub_relocator_alloc_chunk_align (relocator, &ch,
 
685
                                                0x10000, 0x90000,
 
686
                                                3 * sizeof (grub_uint32_t)
 
687
                                                + sizeof (bi), 4,
 
688
                                                GRUB_RELOCATOR_PREFERENCE_NONE);
 
689
        if (err)
 
690
          return err;
 
691
        stack = get_virtual_current_address (ch);
 
692
        stack_target = get_physical_target_address (ch);
 
693
      }
 
694
 
 
695
#ifdef GRUB_MACHINE_EFI
 
696
      err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
 
697
      if (err)
 
698
        return err;
 
699
#endif
 
700
 
 
701
      pagetable = p;
 
702
      fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target);
 
703
 
 
704
      state.cr3 = (pagetable - p0) + p_target;
 
705
      state.rsp = stack_target;
 
706
      state.rip = (((grub_uint64_t) entry_hi) << 32) | entry;
 
707
 
 
708
      stack[0] = entry;
 
709
      stack[1] = bi.tags;
 
710
      stack[2] = kern_end;
 
711
      return grub_relocator64_boot (relocator, state, 0, 0x40000000);
 
712
    }
 
713
  else
 
714
    {
 
715
      struct grub_relocator32_state state;
 
716
      grub_uint32_t *stack;
 
717
      grub_addr_t stack_target;
 
718
 
 
719
      {
 
720
        grub_relocator_chunk_t ch;
 
721
        err = grub_relocator_alloc_chunk_align (relocator, &ch,
 
722
                                                0x10000, 0x90000,
 
723
                                                9 * sizeof (grub_uint32_t)
 
724
                                                + sizeof (bi), 4,
 
725
                                                GRUB_RELOCATOR_PREFERENCE_NONE);
 
726
        if (err)
 
727
          return err;
 
728
        stack = get_virtual_current_address (ch);
 
729
        stack_target = get_physical_target_address (ch);
 
730
      }
 
731
 
 
732
#ifdef GRUB_MACHINE_EFI
 
733
      err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
 
734
      if (err)
 
735
        return err;
 
736
#endif
 
737
 
 
738
      grub_memcpy (&stack[9], &bi, sizeof (bi));
 
739
      state.eip = entry;
 
740
      state.esp = stack_target;
 
741
      state.ebp = stack_target;
 
742
      stack[0] = entry; /* "Return" address.  */
 
743
      stack[1] = bootflags | FREEBSD_RB_BOOTINFO;
 
744
      stack[2] = bootdev;
 
745
      stack[3] = 0;
 
746
      stack[4] = 0;
 
747
      stack[5] = 0;
 
748
      stack[6] = stack_target + 9 * sizeof (grub_uint32_t);
 
749
      stack[7] = bi.tags;
 
750
      stack[8] = kern_end;
 
751
      return grub_relocator32_boot (relocator, state);
 
752
    }
 
753
 
 
754
  /* Not reached.  */
 
755
  return GRUB_ERR_NONE;
 
756
}
 
757
 
 
758
static grub_err_t
 
759
grub_openbsd_boot (void)
 
760
{
 
761
  grub_uint32_t *stack;
 
762
  struct grub_relocator32_state state;
 
763
  void *curarg, *buf0, *arg0;
 
764
  grub_addr_t buf_target;
 
765
  grub_err_t err;
 
766
  grub_size_t tag_buf_len;
 
767
 
 
768
  err = grub_bsd_add_mmap ();
 
769
  if (err)
 
770
    return err;
 
771
 
 
772
  {
 
773
    struct bsd_tag *tag;
 
774
    tag_buf_len = 0;
 
775
    for (tag = tags; tag; tag = tag->next)
 
776
      tag_buf_len = ALIGN_VAR (tag_buf_len
 
777
                               + sizeof (struct grub_openbsd_bootargs)
 
778
                               + tag->len);
 
779
  }
 
780
 
 
781
  buf_target = GRUB_BSD_TEMP_BUFFER - 9 * sizeof (grub_uint32_t);
 
782
  {
 
783
    grub_relocator_chunk_t ch;
 
784
    err = grub_relocator_alloc_chunk_addr (relocator, &ch, buf_target,
 
785
                                           tag_buf_len
 
786
                                           + sizeof (struct grub_openbsd_bootargs)
 
787
                                           + 9 * sizeof (grub_uint32_t));
 
788
    if (err)
 
789
      return err;
 
790
    buf0 = get_virtual_current_address (ch);
 
791
  }
 
792
 
 
793
  stack = (grub_uint32_t *) buf0;
 
794
  arg0 = curarg = stack + 9;
 
795
 
 
796
  {
 
797
    struct bsd_tag *tag;
 
798
    struct grub_openbsd_bootargs *head;
 
799
 
 
800
    for (tag = tags; tag; tag = tag->next)
 
801
      {
 
802
        head = curarg;
 
803
        head->ba_type = tag->type;
 
804
        head->ba_size = tag->len + sizeof (*head);
 
805
        curarg = head + 1;
 
806
        grub_memcpy (curarg, tag->data, tag->len);
 
807
        curarg = (grub_uint8_t *) curarg + tag->len;
 
808
        head->ba_next = (grub_uint8_t *) curarg - (grub_uint8_t *) buf0
 
809
          + buf_target;
 
810
      }
 
811
    head = curarg;
 
812
    head->ba_type = OPENBSD_BOOTARG_END;
 
813
    head->ba_size = 0;
 
814
    head->ba_next = 0;
 
815
  }
 
816
 
 
817
  grub_video_set_mode ("text", 0, 0);
 
818
 
 
819
#ifdef GRUB_MACHINE_EFI
 
820
  err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
 
821
  if (err)
 
822
    return err;
 
823
#endif
 
824
 
 
825
  state.eip = entry;
 
826
  state.ebp = state.esp
 
827
    = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
 
828
  stack[0] = entry;
 
829
  stack[1] = bootflags;
 
830
  stack[2] = openbsd_root;
 
831
  stack[3] = OPENBSD_BOOTARG_APIVER;
 
832
  stack[4] = 0;
 
833
  stack[5] = grub_mmap_get_upper () >> 10;
 
834
  stack[6] = grub_mmap_get_lower () >> 10;
 
835
  stack[7] = (grub_uint8_t *) curarg - (grub_uint8_t *) arg0;
 
836
  stack[8] = ((grub_uint8_t *) arg0 - (grub_uint8_t *) buf0) + buf_target;
 
837
 
 
838
  return grub_relocator32_boot (relocator, state);
 
839
}
 
840
 
 
841
static grub_err_t
 
842
grub_netbsd_setup_video (void)
 
843
{
 
844
  struct grub_video_mode_info mode_info;
 
845
  void *framebuffer;
 
846
  const char *modevar;
 
847
  struct grub_netbsd_btinfo_framebuf params;
 
848
  grub_err_t err;
 
849
  grub_video_driver_id_t driv_id;
 
850
 
 
851
  modevar = grub_env_get ("gfxpayload");
 
852
 
 
853
  /* Now all graphical modes are acceptable.
 
854
     May change in future if we have modes without framebuffer.  */
 
855
  if (modevar && *modevar != 0)
 
856
    {
 
857
      char *tmp;
 
858
      tmp = grub_xasprintf ("%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar);
 
859
      if (! tmp)
 
860
        return grub_errno;
 
861
      err = grub_video_set_mode (tmp, 0, 0);
 
862
      grub_free (tmp);
 
863
    }
 
864
  else
 
865
    err = grub_video_set_mode (NETBSD_DEFAULT_VIDEO_MODE, 0, 0);
 
866
 
 
867
  if (err)
 
868
    return err;
 
869
 
 
870
  driv_id = grub_video_get_driver_id ();
 
871
  if (driv_id == GRUB_VIDEO_DRIVER_NONE)
 
872
    return GRUB_ERR_NONE;
 
873
 
 
874
  err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
 
875
 
 
876
  if (err)
 
877
    return err;
 
878
 
 
879
  params.width = mode_info.width;
 
880
  params.height = mode_info.height;
 
881
  params.bpp = mode_info.bpp;
 
882
  params.pitch = mode_info.pitch;
 
883
  params.flags = 0;
 
884
 
 
885
  params.fbaddr = (grub_addr_t) framebuffer;
 
886
 
 
887
  params.red_mask_size = mode_info.red_mask_size;
 
888
  params.red_field_pos = mode_info.red_field_pos;
 
889
  params.green_mask_size = mode_info.green_mask_size;
 
890
  params.green_field_pos = mode_info.green_field_pos;
 
891
  params.blue_mask_size = mode_info.blue_mask_size;
 
892
  params.blue_field_pos = mode_info.blue_field_pos;
 
893
 
 
894
#ifdef GRUB_MACHINE_PCBIOS
 
895
  /* VESA packed modes may come with zeroed mask sizes, which need
 
896
     to be set here according to DAC Palette width.  If we don't,
 
897
     this results in Linux displaying a black screen.  */
 
898
  if (mode_info.bpp <= 8 && driv_id == GRUB_VIDEO_DRIVER_VBE)
 
899
    {
 
900
      struct grub_vbe_info_block controller_info;
 
901
      int status;
 
902
      int width = 8;
 
903
 
 
904
      status = grub_vbe_bios_get_controller_info (&controller_info);
 
905
 
 
906
      if (status == GRUB_VBE_STATUS_OK &&
 
907
          (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
 
908
        status = grub_vbe_bios_set_dac_palette_width (&width);
 
909
 
 
910
      if (status != GRUB_VBE_STATUS_OK)
 
911
        /* 6 is default after mode reset.  */
 
912
        width = 6;
 
913
 
 
914
      params.red_mask_size = params.green_mask_size
 
915
        = params.blue_mask_size = width;
 
916
    }
 
917
#endif
 
918
 
 
919
  err = grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, &params, sizeof (params));
 
920
  return err;
 
921
}
 
922
 
 
923
static grub_err_t
 
924
grub_netbsd_add_modules (void)
 
925
{
 
926
  struct netbsd_module *mod;
 
927
  unsigned modcnt = 0;
 
928
  struct grub_netbsd_btinfo_modules *mods;
 
929
  unsigned i;
 
930
  grub_err_t err;
 
931
 
 
932
  for (mod = netbsd_mods; mod; mod = mod->next)
 
933
    modcnt++;
 
934
 
 
935
  mods = grub_malloc (sizeof (*mods) + sizeof (mods->mods[0]) * modcnt);
 
936
  if (!mods)
 
937
    return grub_errno;
 
938
 
 
939
  mods->num = modcnt;
 
940
  mods->last_addr = kern_end;
 
941
  for (mod = netbsd_mods, i = 0; mod; i++, mod = mod->next)
 
942
    mods->mods[i] = mod->mod;
 
943
 
 
944
  err = grub_bsd_add_meta (NETBSD_BTINFO_MODULES, mods,
 
945
                           sizeof (*mods) + sizeof (mods->mods[0]) * modcnt);
 
946
  grub_free (mods);
 
947
  return err;
 
948
}
 
949
 
 
950
static grub_err_t
 
951
grub_netbsd_boot (void)
 
952
{
 
953
  struct grub_netbsd_bootinfo *bootinfo;
 
954
  void *curarg, *arg0;
 
955
  grub_addr_t arg_target, stack_target;
 
956
  grub_uint32_t *stack;
 
957
  grub_err_t err;
 
958
  struct grub_relocator32_state state;
 
959
  grub_size_t tag_buf_len = 0;
 
960
  int tag_count = 0;
 
961
 
 
962
  err = grub_bsd_add_mmap ();
 
963
  if (err)
 
964
    return err;
 
965
 
 
966
  err = grub_netbsd_setup_video ();
 
967
  if (err)
 
968
    {
 
969
      grub_print_error ();
 
970
      grub_printf ("Booting however\n");
 
971
      grub_errno = GRUB_ERR_NONE;
 
972
    }
 
973
 
 
974
  err = grub_netbsd_add_modules ();
 
975
  if (err)
 
976
    return err;
 
977
 
 
978
  {
 
979
    struct bsd_tag *tag;
 
980
    tag_buf_len = 0;
 
981
    for (tag = tags; tag; tag = tag->next)
 
982
      {
 
983
        tag_buf_len = ALIGN_VAR (tag_buf_len
 
984
                                 + sizeof (struct grub_netbsd_btinfo_common)
 
985
                                 + tag->len);
 
986
        tag_count++;
 
987
      }
 
988
  }
 
989
 
 
990
  arg_target = kern_end;
 
991
  {
 
992
    grub_relocator_chunk_t ch;
 
993
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
994
                                           arg_target, tag_buf_len
 
995
                                           + sizeof (struct grub_netbsd_bootinfo)
 
996
                                           + tag_count * sizeof (grub_uint32_t));
 
997
    if (err)
 
998
      return err;
 
999
    curarg = get_virtual_current_address (ch);
 
1000
  }
 
1001
 
 
1002
  arg0 = curarg;
 
1003
  bootinfo = (void *) ((grub_uint8_t *) arg0 + tag_buf_len);
 
1004
 
 
1005
  {
 
1006
    struct bsd_tag *tag;
 
1007
    unsigned i;
 
1008
 
 
1009
    bootinfo->bi_count = tag_count;
 
1010
    for (tag = tags, i = 0; tag; i++, tag = tag->next)
 
1011
      {
 
1012
        struct grub_netbsd_btinfo_common *head = curarg;
 
1013
        bootinfo->bi_data[i] = ((grub_uint8_t *) curarg - (grub_uint8_t *) arg0)
 
1014
          + arg_target;
 
1015
        head->type = tag->type;
 
1016
        head->len = tag->len + sizeof (*head);
 
1017
        curarg = head + 1;
 
1018
        grub_memcpy (curarg, tag->data, tag->len);
 
1019
        curarg = (grub_uint8_t *) curarg + tag->len;
 
1020
      }
 
1021
  }
 
1022
 
 
1023
  {
 
1024
    grub_relocator_chunk_t ch;
 
1025
    err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x10000, 0x90000,
 
1026
                                            7 * sizeof (grub_uint32_t), 4,
 
1027
                                            GRUB_RELOCATOR_PREFERENCE_NONE);
 
1028
    if (err)
 
1029
      return err;
 
1030
    stack = get_virtual_current_address (ch);
 
1031
    stack_target = get_physical_target_address (ch);
 
1032
  }
 
1033
 
 
1034
#ifdef GRUB_MACHINE_EFI
 
1035
  err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL);
 
1036
  if (err)
 
1037
    return err;
 
1038
#endif
 
1039
 
 
1040
  state.eip = entry;
 
1041
  state.esp = stack_target;
 
1042
  state.ebp = stack_target;
 
1043
  stack[0] = entry;
 
1044
  stack[1] = bootflags;
 
1045
  stack[2] = 0;
 
1046
  stack[3] = ((grub_uint8_t *) bootinfo - (grub_uint8_t *) arg0) + arg_target;
 
1047
  stack[4] = 0;
 
1048
  stack[5] = grub_mmap_get_upper () >> 10;
 
1049
  stack[6] = grub_mmap_get_lower () >> 10;
 
1050
 
 
1051
  return grub_relocator32_boot (relocator, state);
 
1052
}
 
1053
 
 
1054
static grub_err_t
 
1055
grub_bsd_unload (void)
 
1056
{
 
1057
  struct bsd_tag *tag, *next;
 
1058
  for (tag = tags; tag; tag = next)
 
1059
    {
 
1060
      next = tag->next;
 
1061
      grub_free (tag);
 
1062
    }
 
1063
  tags = NULL;
 
1064
  tags_last = NULL;
 
1065
 
 
1066
  kernel_type = KERNEL_TYPE_NONE;
 
1067
  grub_dl_unref (my_mod);
 
1068
 
 
1069
  grub_relocator_unload (relocator);
 
1070
  relocator = NULL;
 
1071
 
 
1072
  return GRUB_ERR_NONE;
 
1073
}
 
1074
 
 
1075
static grub_err_t
 
1076
grub_bsd_load_aout (grub_file_t file)
 
1077
{
 
1078
  grub_addr_t load_addr, load_end;
 
1079
  int ofs, align_page;
 
1080
  union grub_aout_header ah;
 
1081
  grub_err_t err;
 
1082
  grub_size_t bss_size;
 
1083
 
 
1084
  if ((grub_file_seek (file, 0)) == (grub_off_t) - 1)
 
1085
    return grub_errno;
 
1086
 
 
1087
  if (grub_file_read (file, &ah, sizeof (ah)) != sizeof (ah))
 
1088
    return grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header");
 
1089
 
 
1090
  if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32)
 
1091
    return grub_error (GRUB_ERR_BAD_OS, "invalid a.out header");
 
1092
 
 
1093
  entry = ah.aout32.a_entry & 0xFFFFFF;
 
1094
 
 
1095
  if (AOUT_GETMAGIC (ah.aout32) == AOUT32_ZMAGIC)
 
1096
    {
 
1097
      load_addr = entry;
 
1098
      ofs = 0x1000;
 
1099
      align_page = 0;
 
1100
    }
 
1101
  else
 
1102
    {
 
1103
      load_addr = entry & 0xF00000;
 
1104
      ofs = sizeof (struct grub_aout32_header);
 
1105
      align_page = 1;
 
1106
    }
 
1107
 
 
1108
  if (load_addr < 0x100000)
 
1109
    return grub_error (GRUB_ERR_BAD_OS, "load address below 1M");
 
1110
 
 
1111
  kern_start = load_addr;
 
1112
  load_end = kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data;
 
1113
  if (align_page)
 
1114
    kern_end = ALIGN_PAGE (kern_end);
 
1115
 
 
1116
  if (ah.aout32.a_bss)
 
1117
    {
 
1118
      kern_end += ah.aout32.a_bss;
 
1119
      if (align_page)
 
1120
        kern_end = ALIGN_PAGE (kern_end);
 
1121
 
 
1122
      bss_size = kern_end - load_end;
 
1123
    }
 
1124
  else
 
1125
    bss_size = 0;
 
1126
 
 
1127
  {
 
1128
    grub_relocator_chunk_t ch;
 
1129
 
 
1130
    err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
1131
                                           kern_start, kern_end - kern_start);
 
1132
    if (err)
 
1133
      return err;
 
1134
    kern_chunk_src = get_virtual_current_address (ch);
 
1135
  }
 
1136
 
 
1137
  return grub_aout_load (file, ofs, kern_chunk_src,
 
1138
                         ah.aout32.a_text + ah.aout32.a_data,
 
1139
                         bss_size);
 
1140
}
 
1141
 
 
1142
static int NESTED_FUNC_ATTR
 
1143
grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)),
 
1144
                          Elf32_Phdr *phdr, void *arg __attribute__ ((unused)))
 
1145
{
 
1146
  Elf32_Addr paddr;
 
1147
 
 
1148
  if (phdr->p_type != PT_LOAD
 
1149
      && phdr->p_type != PT_DYNAMIC)
 
1150
      return 0;
 
1151
 
 
1152
  paddr = phdr->p_paddr & 0xFFFFFF;
 
1153
 
 
1154
  if (paddr < kern_start)
 
1155
    kern_start = paddr;
 
1156
 
 
1157
  if (paddr + phdr->p_memsz > kern_end)
 
1158
    kern_end = paddr + phdr->p_memsz;
 
1159
 
 
1160
  return 0;
 
1161
}
 
1162
 
 
1163
static grub_err_t
 
1164
grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load)
 
1165
{
 
1166
  Elf32_Addr paddr;
 
1167
 
 
1168
  if (phdr->p_type != PT_LOAD
 
1169
      && phdr->p_type != PT_DYNAMIC)
 
1170
    {
 
1171
      *do_load = 0;
 
1172
      return 0;
 
1173
    }
 
1174
 
 
1175
  *do_load = 1;
 
1176
  phdr->p_paddr &= 0xFFFFFF;
 
1177
  paddr = phdr->p_paddr;
 
1178
 
 
1179
  *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
 
1180
 
 
1181
  return GRUB_ERR_NONE;
 
1182
}
 
1183
 
 
1184
static int NESTED_FUNC_ATTR
 
1185
grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)),
 
1186
                          Elf64_Phdr *phdr, void *arg __attribute__ ((unused)))
 
1187
{
 
1188
  Elf64_Addr paddr;
 
1189
 
 
1190
  if (phdr->p_type != PT_LOAD
 
1191
      && phdr->p_type != PT_DYNAMIC)
 
1192
    return 0;
 
1193
 
 
1194
  paddr = phdr->p_paddr & 0xffffff;
 
1195
 
 
1196
  if (paddr < kern_start)
 
1197
    kern_start = paddr;
 
1198
 
 
1199
  if (paddr + phdr->p_memsz > kern_end)
 
1200
    kern_end = paddr + phdr->p_memsz;
 
1201
 
 
1202
  return 0;
 
1203
}
 
1204
 
 
1205
static grub_err_t
 
1206
grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load)
 
1207
{
 
1208
  Elf64_Addr paddr;
 
1209
 
 
1210
  if (phdr->p_type != PT_LOAD
 
1211
      && phdr->p_type != PT_DYNAMIC)
 
1212
    {
 
1213
      *do_load = 0;
 
1214
      return 0;
 
1215
    }
 
1216
 
 
1217
  *do_load = 1;
 
1218
  paddr = phdr->p_paddr & 0xffffff;
 
1219
 
 
1220
  *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
 
1221
 
 
1222
  return GRUB_ERR_NONE;
 
1223
}
 
1224
 
 
1225
static grub_err_t
 
1226
grub_bsd_load_elf (grub_elf_t elf)
 
1227
{
 
1228
  grub_err_t err;
 
1229
 
 
1230
  kern_end = 0;
 
1231
  kern_start = ~0;
 
1232
 
 
1233
  if (grub_elf_is_elf32 (elf))
 
1234
    {
 
1235
      grub_relocator_chunk_t ch;
 
1236
 
 
1237
      entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF;
 
1238
      err = grub_elf32_phdr_iterate (elf, grub_bsd_elf32_size_hook, NULL);
 
1239
      if (err)
 
1240
        return err;
 
1241
      err = grub_relocator_alloc_chunk_addr (relocator, &ch,
 
1242
                                             kern_start, kern_end - kern_start);
 
1243
      if (err)
 
1244
        return err;
 
1245
 
 
1246
      kern_chunk_src = get_virtual_current_address (ch);
 
1247
 
 
1248
      err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0);
 
1249
      if (err)
 
1250
        return err;
 
1251
      if (kernel_type != KERNEL_TYPE_OPENBSD)
 
1252
        return GRUB_ERR_NONE;
 
1253
      return grub_openbsd_find_ramdisk32 (elf->file, kern_start,
 
1254
                                          kern_chunk_src, &openbsd_ramdisk);
 
1255
    }
 
1256
  else if (grub_elf_is_elf64 (elf))
 
1257
    {
 
1258
      is_64bit = 1;
 
1259
 
 
1260
      if (! grub_cpuid_has_longmode)
 
1261
        return grub_error (GRUB_ERR_BAD_OS, "your CPU does not implement AMD64 architecture");
 
1262
 
 
1263
      /* FreeBSD has 64-bit entry point.  */
 
1264
      if (kernel_type == KERNEL_TYPE_FREEBSD)
 
1265
        {
 
1266
          entry = elf->ehdr.ehdr64.e_entry & 0xffffffff;
 
1267
          entry_hi = (elf->ehdr.ehdr64.e_entry >> 32) & 0xffffffff;
 
1268
        }
 
1269
      else
 
1270
        {
 
1271
          entry = elf->ehdr.ehdr64.e_entry & 0x0fffffff;
 
1272
          entry_hi = 0;
 
1273
        }
 
1274
 
 
1275
      err = grub_elf64_phdr_iterate (elf, grub_bsd_elf64_size_hook, NULL);
 
1276
      if (err)
 
1277
        return err;
 
1278
 
 
1279
      grub_dprintf ("bsd", "kern_start = %lx, kern_end = %lx\n",
 
1280
                    (unsigned long) kern_start, (unsigned long) kern_end);
 
1281
      {
 
1282
        grub_relocator_chunk_t ch;
 
1283
 
 
1284
        err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
 
1285
                                               kern_end - kern_start);
 
1286
        if (err)
 
1287
          return err;
 
1288
        kern_chunk_src = get_virtual_current_address (ch);
 
1289
      }
 
1290
 
 
1291
      err = grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0);
 
1292
      if (err)
 
1293
        return err;
 
1294
      if (kernel_type != KERNEL_TYPE_OPENBSD)
 
1295
        return GRUB_ERR_NONE;
 
1296
      return grub_openbsd_find_ramdisk64 (elf->file, kern_start,
 
1297
                                          kern_chunk_src, &openbsd_ramdisk);
 
1298
    }
 
1299
  else
 
1300
    return grub_error (GRUB_ERR_BAD_OS, "invalid ELF");
 
1301
}
 
1302
 
 
1303
static grub_err_t
 
1304
grub_bsd_load (int argc, char *argv[])
 
1305
{
 
1306
  grub_file_t file;
 
1307
  grub_elf_t elf;
 
1308
 
 
1309
  grub_dl_ref (my_mod);
 
1310
 
 
1311
  grub_loader_unset ();
 
1312
 
 
1313
  grub_memset (&openbsd_ramdisk, 0, sizeof (openbsd_ramdisk));
 
1314
 
 
1315
  if (argc == 0)
 
1316
    {
 
1317
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
 
1318
      goto fail;
 
1319
    }
 
1320
 
 
1321
  file = grub_file_open (argv[0]);
 
1322
  if (!file)
 
1323
    goto fail;
 
1324
 
 
1325
  relocator = grub_relocator_new ();
 
1326
 
 
1327
  elf = grub_elf_file (file);
 
1328
  if (elf)
 
1329
    {
 
1330
      is_elf_kernel = 1;
 
1331
      grub_bsd_load_elf (elf);
 
1332
      grub_elf_close (elf);
 
1333
    }
 
1334
  else
 
1335
    {
 
1336
      is_elf_kernel = 0;
 
1337
      grub_errno = 0;
 
1338
      grub_bsd_load_aout (file);
 
1339
      grub_file_close (file);
 
1340
    }
 
1341
 
 
1342
  kern_end = ALIGN_PAGE (kern_end);
 
1343
 
 
1344
fail:
 
1345
 
 
1346
  if (grub_errno != GRUB_ERR_NONE)
 
1347
    grub_dl_unref (my_mod);
 
1348
 
 
1349
  return grub_errno;
 
1350
}
 
1351
 
 
1352
static grub_uint32_t
 
1353
grub_bsd_parse_flags (const struct grub_arg_list *state,
 
1354
                      const grub_uint32_t * flags)
 
1355
{
 
1356
  grub_uint32_t result = 0;
 
1357
  unsigned i;
 
1358
 
 
1359
  for (i = 0; flags[i]; i++)
 
1360
    if (state[i].set)
 
1361
      result |= flags[i];
 
1362
 
 
1363
  return result;
 
1364
}
 
1365
 
 
1366
static grub_err_t
 
1367
grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
 
1368
{
 
1369
  kernel_type = KERNEL_TYPE_FREEBSD;
 
1370
  bootflags = grub_bsd_parse_flags (ctxt->state, freebsd_flags);
 
1371
 
 
1372
  if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
 
1373
    {
 
1374
      kern_end = ALIGN_PAGE (kern_end);
 
1375
      if (is_elf_kernel)
 
1376
        {
 
1377
          grub_err_t err;
 
1378
          grub_uint64_t data = 0;
 
1379
          grub_file_t file;
 
1380
          int len = is_64bit ? 8 : 4;
 
1381
 
 
1382
          err = grub_freebsd_add_meta_module (argv[0], is_64bit
 
1383
                                              ? FREEBSD_MODTYPE_KERNEL64
 
1384
                                              : FREEBSD_MODTYPE_KERNEL,
 
1385
                                              argc - 1, argv + 1,
 
1386
                                              kern_start,
 
1387
                                              kern_end - kern_start);
 
1388
          if (err)
 
1389
            return err;
 
1390
 
 
1391
          file = grub_file_open (argv[0]);
 
1392
          if (! file)
 
1393
            return grub_errno;
 
1394
 
 
1395
          if (is_64bit)
 
1396
            err = grub_freebsd_load_elf_meta64 (relocator, file, &kern_end);
 
1397
          else
 
1398
            err = grub_freebsd_load_elf_meta32 (relocator, file, &kern_end);
 
1399
          if (err)
 
1400
            return err;
 
1401
 
 
1402
          err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
 
1403
                                   FREEBSD_MODINFOMD_HOWTO, &data, 4);
 
1404
          if (err)
 
1405
            return err;
 
1406
 
 
1407
          err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
 
1408
                                       FREEBSD_MODINFOMD_ENVP, &data, len);
 
1409
          if (err)
 
1410
            return err;
 
1411
 
 
1412
          err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA |
 
1413
                                   FREEBSD_MODINFOMD_KERNEND, &data, len);
 
1414
          if (err)
 
1415
            return err;
 
1416
        }
 
1417
      grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 0);
 
1418
    }
 
1419
 
 
1420
  return grub_errno;
 
1421
}
 
1422
 
 
1423
static grub_err_t
 
1424
grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
 
1425
{
 
1426
  grub_uint32_t bootdev;
 
1427
 
 
1428
  kernel_type = KERNEL_TYPE_OPENBSD;
 
1429
  bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags);
 
1430
 
 
1431
  if (ctxt->state[OPENBSD_ROOT_ARG].set)
 
1432
    {
 
1433
      const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg;
 
1434
      int unit, part;
 
1435
      if (*(arg++) != 'w' || *(arg++) != 'd')
 
1436
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1437
                           "only device specifications of form "
 
1438
                           "wd<number><lowercase letter> are supported");
 
1439
 
 
1440
      unit = grub_strtoul (arg, (char **) &arg, 10);
 
1441
      if (! (arg && *arg >= 'a' && *arg <= 'z'))
 
1442
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1443
                           "only device specifications of form "
 
1444
                           "wd<number><lowercase letter> are supported");
 
1445
 
 
1446
      part = *arg - 'a';
 
1447
 
 
1448
      bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) +
 
1449
                 (part << OPENBSD_B_PARTSHIFT));
 
1450
    }
 
1451
  else
 
1452
    bootdev = 0;
 
1453
 
 
1454
  if (ctxt->state[OPENBSD_SERIAL_ARG].set)
 
1455
    {
 
1456
      struct grub_openbsd_bootarg_console serial;
 
1457
      char *ptr;
 
1458
      unsigned port = 0;
 
1459
      unsigned speed = 9600;
 
1460
 
 
1461
      grub_memset (&serial, 0, sizeof (serial));
 
1462
 
 
1463
      if (ctxt->state[OPENBSD_SERIAL_ARG].arg)
 
1464
        {
 
1465
          ptr = ctxt->state[OPENBSD_SERIAL_ARG].arg;
 
1466
          if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0)
 
1467
            return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1468
                               "only com0-com3 are supported");
 
1469
          ptr += sizeof ("com") - 1;
 
1470
          port = grub_strtoul (ptr, &ptr, 0);
 
1471
          if (port >= 4)
 
1472
            return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1473
                               "only com0-com3 are supported");
 
1474
          if (*ptr == ',')
 
1475
            {
 
1476
              ptr++; 
 
1477
              speed = grub_strtoul (ptr, &ptr, 0);
 
1478
              if (grub_errno)
 
1479
                return grub_errno;
 
1480
            }
 
1481
        }
 
1482
 
 
1483
      serial.device = (GRUB_OPENBSD_COM_MAJOR << 8) | port;
 
1484
      serial.speed = speed;
 
1485
          
 
1486
      grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial));
 
1487
      bootflags |= OPENBSD_RB_SERCONS;
 
1488
    }
 
1489
  else
 
1490
    {
 
1491
      struct grub_openbsd_bootarg_console serial;
 
1492
 
 
1493
      grub_memset (&serial, 0, sizeof (serial));
 
1494
      serial.device = (GRUB_OPENBSD_VGA_MAJOR << 8);
 
1495
      grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial));
 
1496
      bootflags &= ~OPENBSD_RB_SERCONS;
 
1497
    }
 
1498
 
 
1499
  if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
 
1500
    {
 
1501
      grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 0);
 
1502
      openbsd_root = bootdev;
 
1503
    }
 
1504
 
 
1505
  return grub_errno;
 
1506
}
 
1507
 
 
1508
static grub_err_t
 
1509
grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
 
1510
{
 
1511
  grub_err_t err;
 
1512
  kernel_type = KERNEL_TYPE_NETBSD;
 
1513
  bootflags = grub_bsd_parse_flags (ctxt->state, netbsd_flags);
 
1514
 
 
1515
  if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
 
1516
    {
 
1517
      if (is_elf_kernel)
 
1518
        {
 
1519
          grub_file_t file;
 
1520
 
 
1521
          file = grub_file_open (argv[0]);
 
1522
          if (! file)
 
1523
            return grub_errno;
 
1524
 
 
1525
          if (is_64bit)
 
1526
            err = grub_netbsd_load_elf_meta64 (relocator, file, &kern_end);
 
1527
          else
 
1528
            err = grub_netbsd_load_elf_meta32 (relocator, file, &kern_end);
 
1529
          if (err)
 
1530
            return err;
 
1531
        }
 
1532
 
 
1533
      {
 
1534
        char bootpath[GRUB_NETBSD_MAX_BOOTPATH_LEN];
 
1535
        char *name;
 
1536
        name = grub_strrchr (argv[0], '/');
 
1537
        if (name)
 
1538
          name++;
 
1539
        else
 
1540
          name = argv[0];
 
1541
        grub_memset (bootpath, 0, sizeof (bootpath));
 
1542
        grub_strncpy (bootpath, name, sizeof (bootpath) - 1);
 
1543
        grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath));
 
1544
      }
 
1545
 
 
1546
      if (ctxt->state[NETBSD_ROOT_ARG].set)
 
1547
        {
 
1548
          char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN];
 
1549
          grub_memset (root, 0, sizeof (root));
 
1550
          grub_strncpy (root, ctxt->state[NETBSD_ROOT_ARG].arg,
 
1551
                        sizeof (root) - 1);
 
1552
          grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root));
 
1553
        }
 
1554
      if (ctxt->state[NETBSD_SERIAL_ARG].set)
 
1555
        {
 
1556
          struct grub_netbsd_btinfo_serial serial;
 
1557
          char *ptr;
 
1558
 
 
1559
          grub_memset (&serial, 0, sizeof (serial));
 
1560
          grub_strcpy (serial.devname, "com");
 
1561
 
 
1562
          serial.addr = grub_ns8250_hw_get_port (0);
 
1563
          serial.speed = 9600;
 
1564
 
 
1565
          if (ctxt->state[NETBSD_SERIAL_ARG].arg)
 
1566
            {
 
1567
              ptr = ctxt->state[NETBSD_SERIAL_ARG].arg;
 
1568
              if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0)
 
1569
                {
 
1570
                  ptr += sizeof ("com") - 1;
 
1571
                  serial.addr 
 
1572
                    = grub_ns8250_hw_get_port (grub_strtoul (ptr, &ptr, 0));
 
1573
                }
 
1574
              else
 
1575
                serial.addr = grub_strtoul (ptr, &ptr, 0);
 
1576
              if (grub_errno)
 
1577
                return grub_errno;
 
1578
 
 
1579
              if (*ptr == ',')
 
1580
                {
 
1581
                  ptr++;
 
1582
                  serial.speed = grub_strtoul (ptr, &ptr, 0);
 
1583
                  if (grub_errno)
 
1584
                    return grub_errno;
 
1585
                }
 
1586
            }
 
1587
 
 
1588
          grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &serial, sizeof (serial));
 
1589
        }
 
1590
      else
 
1591
        {
 
1592
          struct grub_netbsd_btinfo_serial cons;
 
1593
 
 
1594
          grub_memset (&cons, 0, sizeof (cons));
 
1595
          grub_strcpy (cons.devname, "pc");
 
1596
 
 
1597
          grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &cons, sizeof (cons));
 
1598
        }
 
1599
 
 
1600
      grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 0);
 
1601
    }
 
1602
 
 
1603
  return grub_errno;
 
1604
}
 
1605
 
 
1606
static grub_err_t
 
1607
grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)),
 
1608
                          int argc, char *argv[])
 
1609
{
 
1610
  grub_file_t file = 0;
 
1611
  char *buf = 0, *curr, *next;
 
1612
  int len;
 
1613
 
 
1614
  if (kernel_type == KERNEL_TYPE_NONE)
 
1615
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1616
                       "you need to load the kernel first");
 
1617
 
 
1618
  if (kernel_type != KERNEL_TYPE_FREEBSD)
 
1619
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1620
                       "only FreeBSD supports environment");
 
1621
 
 
1622
  if (argc == 0)
 
1623
    {
 
1624
      grub_error (GRUB_ERR_BAD_ARGUMENT, "no filename");
 
1625
      goto fail;
 
1626
    }
 
1627
 
 
1628
  file = grub_file_open (argv[0]);
 
1629
  if ((!file) || (!file->size))
 
1630
    goto fail;
 
1631
 
 
1632
  len = file->size;
 
1633
  buf = grub_malloc (len + 1);
 
1634
  if (!buf)
 
1635
    goto fail;
 
1636
 
 
1637
  if (grub_file_read (file, buf, len) != len)
 
1638
    goto fail;
 
1639
 
 
1640
  buf[len] = 0;
 
1641
 
 
1642
  next = buf;
 
1643
  while (next)
 
1644
    {
 
1645
      char *p;
 
1646
 
 
1647
      curr = next;
 
1648
      next = grub_strchr (curr, '\n');
 
1649
      if (next)
 
1650
        {
 
1651
 
 
1652
          p = next - 1;
 
1653
          while (p > curr)
 
1654
            {
 
1655
              if ((*p != '\r') && (*p != ' ') && (*p != '\t'))
 
1656
                break;
 
1657
              p--;
 
1658
            }
 
1659
 
 
1660
          if ((p > curr) && (*p == '"'))
 
1661
            p--;
 
1662
 
 
1663
          *(p + 1) = 0;
 
1664
          next++;
 
1665
        }
 
1666
 
 
1667
      if (*curr == '#')
 
1668
        continue;
 
1669
 
 
1670
      p = grub_strchr (curr, '=');
 
1671
      if (!p)
 
1672
        continue;
 
1673
 
 
1674
      *(p++) = 0;
 
1675
 
 
1676
      if (*curr)
 
1677
        {
 
1678
          char *name;
 
1679
 
 
1680
          if (*p == '"')
 
1681
            p++;
 
1682
 
 
1683
          name = grub_xasprintf ("kFreeBSD.%s", curr);
 
1684
          if (!name)
 
1685
            goto fail;
 
1686
          if (grub_env_set (name, p))
 
1687
            {
 
1688
              grub_free (name);
 
1689
              goto fail;
 
1690
            }
 
1691
          grub_free (name);
 
1692
        }
 
1693
    }
 
1694
 
 
1695
fail:
 
1696
  grub_free (buf);
 
1697
 
 
1698
  if (file)
 
1699
    grub_file_close (file);
 
1700
 
 
1701
  return grub_errno;
 
1702
}
 
1703
 
 
1704
static grub_err_t
 
1705
grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
 
1706
                         int argc, char *argv[])
 
1707
{
 
1708
  grub_file_t file = 0;
 
1709
  int modargc;
 
1710
  char **modargv;
 
1711
  char *type;
 
1712
  grub_err_t err;
 
1713
  void *src;
 
1714
 
 
1715
  if (kernel_type != KERNEL_TYPE_FREEBSD)
 
1716
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "no FreeBSD loaded");
 
1717
 
 
1718
  if (!is_elf_kernel)
 
1719
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1720
                       "only ELF kernel supports module");
 
1721
 
 
1722
  /* List the current modules if no parameter.  */
 
1723
  if (!argc)
 
1724
    {
 
1725
      grub_freebsd_list_modules ();
 
1726
      return 0;
 
1727
    }
 
1728
 
 
1729
  file = grub_file_open (argv[0]);
 
1730
  if ((!file) || (!file->size))
 
1731
    goto fail;
 
1732
 
 
1733
  {
 
1734
    grub_relocator_chunk_t ch;
 
1735
    err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, 
 
1736
                                           file->size);
 
1737
    if (err)
 
1738
      goto fail;
 
1739
    src = get_virtual_current_address (ch);
 
1740
  }
 
1741
 
 
1742
 
 
1743
  grub_file_read (file, src, file->size);
 
1744
  if (grub_errno)
 
1745
    goto fail;
 
1746
 
 
1747
  modargc = argc - 1;
 
1748
  modargv = argv + 1;
 
1749
 
 
1750
  if (modargc && (! grub_memcmp (modargv[0], "type=", 5)))
 
1751
    {
 
1752
      type = &modargv[0][5];
 
1753
      modargc--;
 
1754
      modargv++;
 
1755
    }
 
1756
  else
 
1757
    type = FREEBSD_MODTYPE_RAW;
 
1758
 
 
1759
  err = grub_freebsd_add_meta_module (argv[0], type, modargc, modargv,
 
1760
                                      kern_end, file->size);
 
1761
  if (err)
 
1762
    goto fail;
 
1763
 
 
1764
  kern_end = ALIGN_PAGE (kern_end + file->size);
 
1765
 
 
1766
fail:
 
1767
  if (file)
 
1768
    grub_file_close (file);
 
1769
 
 
1770
  return grub_errno;
 
1771
}
 
1772
 
 
1773
static grub_err_t
 
1774
grub_netbsd_module_load (char *filename, grub_uint32_t type)
 
1775
{
 
1776
  grub_file_t file = 0;
 
1777
  void *src;
 
1778
  grub_err_t err;
 
1779
 
 
1780
  file = grub_file_open (filename);
 
1781
  if ((!file) || (!file->size))
 
1782
    goto fail;
 
1783
 
 
1784
  {
 
1785
    grub_relocator_chunk_t ch;
 
1786
    err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, 
 
1787
                                           file->size);
 
1788
    if (err)
 
1789
      goto fail;
 
1790
 
 
1791
    src = get_virtual_current_address (ch);
 
1792
  }
 
1793
 
 
1794
  grub_file_read (file, src, file->size);
 
1795
  if (grub_errno)
 
1796
    goto fail;
 
1797
 
 
1798
  err = grub_netbsd_add_meta_module (filename, type, kern_end, file->size);
 
1799
 
 
1800
  if (err)
 
1801
    goto fail;
 
1802
 
 
1803
  kern_end = ALIGN_PAGE (kern_end + file->size);
 
1804
 
 
1805
fail:
 
1806
  if (file)
 
1807
    grub_file_close (file);
 
1808
 
 
1809
  return grub_errno;
 
1810
}
 
1811
 
 
1812
static grub_err_t
 
1813
grub_cmd_netbsd_module (grub_command_t cmd,
 
1814
                        int argc, char *argv[])
 
1815
{
 
1816
  grub_uint32_t type;
 
1817
 
 
1818
  if (kernel_type != KERNEL_TYPE_NETBSD)
 
1819
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "no NetBSD loaded");
 
1820
 
 
1821
  if (!is_elf_kernel)
 
1822
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1823
                       "only ELF kernel supports module");
 
1824
 
 
1825
  /* List the current modules if no parameter.  */
 
1826
  if (!argc)
 
1827
    {
 
1828
      grub_netbsd_list_modules ();
 
1829
      return 0;
 
1830
    }
 
1831
 
 
1832
  if (grub_strcmp (cmd->name, "knetbsd_module_elf") == 0)
 
1833
    type = GRUB_NETBSD_MODULE_ELF;
 
1834
  else
 
1835
    type = GRUB_NETBSD_MODULE_RAW;
 
1836
 
 
1837
  return grub_netbsd_module_load (argv[0], type);
 
1838
}
 
1839
 
 
1840
static grub_err_t
 
1841
grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
 
1842
                             int argc, char *argv[])
 
1843
{
 
1844
  grub_file_t file = 0;
 
1845
  grub_err_t err;
 
1846
 
 
1847
  if (kernel_type == KERNEL_TYPE_NONE)
 
1848
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1849
                       "you need to load the kernel first");
 
1850
 
 
1851
  if (kernel_type != KERNEL_TYPE_FREEBSD)
 
1852
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1853
                       "only FreeBSD supports module");
 
1854
 
 
1855
  if (! is_elf_kernel)
 
1856
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
1857
                       "only ELF kernel supports module");
 
1858
 
 
1859
  /* List the current modules if no parameter.  */
 
1860
  if (! argc)
 
1861
    {
 
1862
      grub_freebsd_list_modules ();
 
1863
      return 0;
 
1864
    }
 
1865
 
 
1866
  file = grub_file_open (argv[0]);
 
1867
  if (!file)
 
1868
    return grub_errno;
 
1869
  if (!file->size)
 
1870
    {
 
1871
      grub_file_close (file);
 
1872
      return grub_errno;
 
1873
    }
 
1874
 
 
1875
  if (is_64bit)
 
1876
    err = grub_freebsd_load_elfmodule_obj64 (relocator, file,
 
1877
                                             argc, argv, &kern_end);
 
1878
  else
 
1879
    err = grub_freebsd_load_elfmodule32 (relocator, file,
 
1880
                                         argc, argv, &kern_end);
 
1881
  grub_file_close (file);
 
1882
 
 
1883
  return err;
 
1884
}
 
1885
 
 
1886
static grub_err_t
 
1887
grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)),
 
1888
                      int argc, char *args[])
 
1889
{
 
1890
  grub_file_t file;
 
1891
  grub_size_t size;
 
1892
 
 
1893
  if (argc != 1)
 
1894
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 
1895
 
 
1896
  if (kernel_type != KERNEL_TYPE_OPENBSD)
 
1897
    return grub_error (GRUB_ERR_BAD_OS, "no kOpenBSD loaded");
 
1898
 
 
1899
  if (!openbsd_ramdisk.max_size)
 
1900
    return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk");
 
1901
 
 
1902
  file = grub_file_open (args[0]);
 
1903
  if (! file)
 
1904
    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
 
1905
                       "couldn't load ramdisk");
 
1906
 
 
1907
  size = grub_file_size (file);
 
1908
 
 
1909
  if (size > openbsd_ramdisk.max_size)
 
1910
    {
 
1911
      grub_file_close (file);
 
1912
      return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD supports ramdisk only"
 
1913
                         " up to %u bytes, however you supplied a %u bytes one",
 
1914
                         openbsd_ramdisk.max_size, size);
 
1915
    }
 
1916
 
 
1917
  if (grub_file_read (file, openbsd_ramdisk.target, size)
 
1918
      != (grub_ssize_t) (size))
 
1919
    {
 
1920
      grub_file_close (file);
 
1921
      grub_error_push ();
 
1922
      return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
 
1923
    }
 
1924
  grub_memset (openbsd_ramdisk.target + size, 0,
 
1925
               openbsd_ramdisk.max_size - size);
 
1926
  *openbsd_ramdisk.size = ALIGN_UP (size, 512);
 
1927
 
 
1928
  return GRUB_ERR_NONE;
 
1929
}
 
1930
 
 
1931
static grub_extcmd_t cmd_freebsd, cmd_openbsd, cmd_netbsd;
 
1932
static grub_command_t cmd_freebsd_loadenv, cmd_freebsd_module;
 
1933
static grub_command_t cmd_netbsd_module, cmd_freebsd_module_elf;
 
1934
static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk;
 
1935
 
 
1936
GRUB_MOD_INIT (bsd)
 
1937
{
 
1938
  /* Net and OpenBSD kernels are often compressed.  */
 
1939
  grub_dl_load ("gzio");
 
1940
 
 
1941
  cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, 0,
 
1942
                                      N_("FILE"), N_("Load kernel of FreeBSD."),
 
1943
                                      freebsd_opts);
 
1944
  cmd_openbsd = grub_register_extcmd ("kopenbsd", grub_cmd_openbsd, 0,
 
1945
                                      N_("FILE"), N_("Load kernel of OpenBSD."),
 
1946
                                      openbsd_opts);
 
1947
  cmd_netbsd = grub_register_extcmd ("knetbsd", grub_cmd_netbsd,  0,
 
1948
                                     N_("FILE"), N_("Load kernel of NetBSD."),
 
1949
                                     netbsd_opts);
 
1950
  cmd_freebsd_loadenv =
 
1951
    grub_register_command ("kfreebsd_loadenv", grub_cmd_freebsd_loadenv,
 
1952
                           0, N_("Load FreeBSD env."));
 
1953
  cmd_freebsd_module =
 
1954
    grub_register_command ("kfreebsd_module", grub_cmd_freebsd_module,
 
1955
                           0, N_("Load FreeBSD kernel module."));
 
1956
  cmd_netbsd_module =
 
1957
    grub_register_command ("knetbsd_module", grub_cmd_netbsd_module,
 
1958
                           0, N_("Load NetBSD kernel module."));
 
1959
  cmd_netbsd_module_elf =
 
1960
    grub_register_command ("knetbsd_module_elf", grub_cmd_netbsd_module,
 
1961
                           0, N_("Load NetBSD kernel module (ELF)."));
 
1962
  cmd_freebsd_module_elf =
 
1963
    grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf,
 
1964
                           0, N_("Load FreeBSD kernel module (ELF)."));
 
1965
 
 
1966
  cmd_openbsd_ramdisk = grub_register_command ("kopenbsd_ramdisk",
 
1967
                                               grub_cmd_openbsd_ramdisk, 0,
 
1968
                                               "Load kOpenBSD ramdisk. ");
 
1969
 
 
1970
  my_mod = mod;
 
1971
}
 
1972
 
 
1973
GRUB_MOD_FINI (bsd)
 
1974
{
 
1975
  grub_unregister_extcmd (cmd_freebsd);
 
1976
  grub_unregister_extcmd (cmd_openbsd);
 
1977
  grub_unregister_extcmd (cmd_netbsd);
 
1978
 
 
1979
  grub_unregister_command (cmd_freebsd_loadenv);
 
1980
  grub_unregister_command (cmd_freebsd_module);
 
1981
  grub_unregister_command (cmd_netbsd_module);
 
1982
  grub_unregister_command (cmd_freebsd_module_elf);
 
1983
  grub_unregister_command (cmd_netbsd_module_elf);
 
1984
  grub_unregister_command (cmd_openbsd_ramdisk);
 
1985
 
 
1986
  grub_bsd_unload ();
 
1987
}