summaryrefslogtreecommitdiffstats
path: root/grub-core/kern/emu
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/kern/emu')
-rw-r--r--grub-core/kern/emu/argp_common.c41
-rw-r--r--grub-core/kern/emu/cache.c35
-rw-r--r--grub-core/kern/emu/cache_s.S15
-rw-r--r--grub-core/kern/emu/full.c69
-rw-r--r--grub-core/kern/emu/hostdisk.c686
-rw-r--r--grub-core/kern/emu/hostfs.c200
-rw-r--r--grub-core/kern/emu/lite.c47
-rw-r--r--grub-core/kern/emu/main.c286
-rw-r--r--grub-core/kern/emu/misc.c216
-rw-r--r--grub-core/kern/emu/mm.c75
-rw-r--r--grub-core/kern/emu/time.c46
11 files changed, 1716 insertions, 0 deletions
diff --git a/grub-core/kern/emu/argp_common.c b/grub-core/kern/emu/argp_common.c
new file mode 100644
index 0000000..1668858
--- /dev/null
+++ b/grub-core/kern/emu/argp_common.c
@@ -0,0 +1,41 @@
+/* grub-setup.c - make GRUB usable */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#pragma GCC diagnostic ignored "-Wmissing-declarations"
+
+#define _GNU_SOURCE 1
+#include <stdlib.h>
+#include <unistd.h>
+#include <progname.h>
+#include <argp.h>
+
+/* Print the version information. */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+ fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
+}
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Set the bug report address */
+const char *argp_program_bug_address = "<"PACKAGE_BUGREPORT">";
diff --git a/grub-core/kern/emu/cache.c b/grub-core/kern/emu/cache.c
new file mode 100644
index 0000000..113682c
--- /dev/null
+++ b/grub-core/kern/emu/cache.c
@@ -0,0 +1,35 @@
+#ifndef GRUB_MACHINE_EMU
+#error "This source is only meant for grub-emu platform"
+#endif
+
+#include <grub/cache.h>
+
+#if defined(__ia64__)
+#include "../ia64/cache.c"
+#elif defined (__arm__) || defined (__aarch64__)
+
+void __clear_cache (void *beg, void *end);
+
+void
+grub_arch_sync_caches (void *address, grub_size_t len)
+{
+ __clear_cache (address, (char *) address + len);
+}
+
+#elif defined (__mips__)
+void _flush_cache (void *address, grub_size_t len, int type);
+
+void
+grub_arch_sync_caches (void *address, grub_size_t len)
+{
+ return _flush_cache (address, len, 0);
+}
+
+#elif defined(__riscv)
+void
+grub_arch_sync_caches (void *address, grub_size_t len)
+{
+}
+
+#endif
+
diff --git a/grub-core/kern/emu/cache_s.S b/grub-core/kern/emu/cache_s.S
new file mode 100644
index 0000000..2245cdd
--- /dev/null
+++ b/grub-core/kern/emu/cache_s.S
@@ -0,0 +1,15 @@
+#ifndef GRUB_MACHINE_EMU
+#error "This source is only meant for grub-emu platform"
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+/* Nothing is necessary. */
+#elif defined(__sparc__)
+#include "../sparc64/cache.S"
+#elif defined(__powerpc__)
+#include "../powerpc/cache.S"
+#elif defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \
+ defined(__mips__) || defined(__riscv)
+#else
+#error "No target cpu type is defined"
+#endif
diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c
new file mode 100644
index 0000000..e8d63b1
--- /dev/null
+++ b/grub-core/kern/emu/full.c
@@ -0,0 +1,69 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/dl.h>
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/disk.h>
+
+const int grub_no_modules = 1;
+
+void
+grub_register_exported_symbols (void)
+{
+}
+
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+ (void) ehdr;
+ return GRUB_ERR_BAD_MODULE;
+}
+
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ Elf_Shdr *s, grub_dl_segment_t seg)
+{
+ (void) mod;
+ (void) ehdr;
+ (void) s;
+ (void) seg;
+ return GRUB_ERR_BAD_MODULE;
+}
+
+#if !defined (__i386__) && !defined (__x86_64__)
+grub_err_t
+grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
+ grub_size_t *tramp, grub_size_t *got)
+{
+ *tramp = 0;
+ *got = 0;
+ return GRUB_ERR_BAD_MODULE;
+}
+#endif
+
+#ifdef GRUB_LINKER_HAVE_INIT
+void
+grub_arch_dl_init_linker (void)
+{
+}
+#endif
+
diff --git a/grub-core/kern/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c
new file mode 100644
index 0000000..d975265
--- /dev/null
+++ b/grub-core/kern/emu/hostdisk.c
@@ -0,0 +1,686 @@
+/* hostdisk.c - emulate biosdisk */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifdef __linux__
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+# ifndef BLKFLSBUF
+# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
+# endif /* ! BLKFLSBUF */
+#endif /* __linux__ */
+
+static struct
+{
+ char *drive;
+ char *device;
+ int device_map;
+} map[256];
+
+static int
+unescape_cmp (const char *a, const char *b_escaped)
+{
+ while (*a || *b_escaped)
+ {
+ if (*b_escaped == '\\' && b_escaped[1] != 0)
+ b_escaped++;
+ if (*a < *b_escaped)
+ return -1;
+ if (*a > *b_escaped)
+ return +1;
+ a++;
+ b_escaped++;
+ }
+ if (*a)
+ return +1;
+ if (*b_escaped)
+ return -1;
+ return 0;
+}
+
+static int
+find_grub_drive (const char *name)
+{
+ unsigned int i;
+
+ if (name)
+ {
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (map[i].drive && unescape_cmp (map[i].drive, name) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+static int
+find_free_slot (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (! map[i].drive)
+ return i;
+
+ return -1;
+}
+
+static int
+grub_util_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+ grub_disk_pull_t pull)
+{
+ unsigned i;
+
+ if (pull != GRUB_DISK_PULL_NONE)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (map[i].drive && hook (map[i].drive, hook_data))
+ return 1;
+
+ return 0;
+}
+
+static grub_err_t
+grub_util_biosdisk_open (const char *name, grub_disk_t disk)
+{
+ int drive;
+ struct grub_util_hostdisk_data *data;
+
+ drive = find_grub_drive (name);
+ grub_util_info ("drive = %d", drive);
+ if (drive < 0)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "no mapping exists for `%s'", name);
+
+ disk->id = drive;
+ disk->data = data = xmalloc (sizeof (struct grub_util_hostdisk_data));
+ data->dev = NULL;
+ data->access_mode = 0;
+ data->fd = GRUB_UTIL_FD_INVALID;
+ data->is_disk = 0;
+ data->device_map = map[drive].device_map;
+
+ /* Get the size. */
+ {
+ grub_util_fd_t fd;
+
+ fd = grub_util_fd_open (map[drive].device, GRUB_UTIL_FD_O_RDONLY);
+
+ if (!GRUB_UTIL_FD_IS_VALID(fd))
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("cannot open `%s': %s"),
+ map[drive].device, grub_util_fd_strerror ());
+
+ disk->total_sectors = grub_util_get_fd_size (fd, map[drive].device,
+ &disk->log_sector_size);
+ disk->total_sectors >>= disk->log_sector_size;
+ disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
+
+#if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
+ {
+ struct stat st;
+# if GRUB_DISK_DEVS_ARE_CHAR
+ if (fstat (fd, &st) >= 0 && S_ISCHR (st.st_mode))
+# else
+ if (fstat (fd, &st) >= 0 && S_ISBLK (st.st_mode))
+# endif
+ data->is_disk = 1;
+ }
+#endif
+
+ grub_util_fd_close (fd);
+
+ grub_util_info ("the size of %s is %" GRUB_HOST_PRIuLONG_LONG,
+ name, (unsigned long long) disk->total_sectors);
+
+ return GRUB_ERR_NONE;
+ }
+}
+
+const char *
+grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
+{
+ unsigned int i;
+ char *canon;
+
+ canon = grub_canonicalize_file_name (os_disk);
+ if (!canon)
+ canon = xstrdup (os_disk);
+
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (! map[i].device)
+ break;
+ else if (strcmp (map[i].device, canon) == 0)
+ {
+ free (canon);
+ return map[i].drive;
+ }
+
+ if (!add)
+ {
+ free (canon);
+ return NULL;
+ }
+
+ if (i == ARRAY_SIZE (map))
+ /* TRANSLATORS: it refers to the lack of free slots. */
+ grub_util_error ("%s", _("device count exceeds limit"));
+
+ map[i].device = canon;
+ map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
+ strcpy (map[i].drive, "hostdisk/");
+ strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
+ map[i].device_map = 0;
+
+ grub_hostdisk_flush_initial_buffer (os_disk);
+
+ return map[i].drive;
+}
+
+#ifndef __linux__
+grub_util_fd_t
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
+ grub_disk_addr_t *max)
+{
+ grub_util_fd_t fd;
+ struct grub_util_hostdisk_data *data = disk->data;
+
+ *max = ~0ULL;
+
+ flags |= GRUB_UTIL_FD_O_SYNC;
+
+ if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 &&
+ data->access_mode == (flags & O_ACCMODE))
+ {
+ grub_dprintf ("hostdisk", "reusing open device `%s'\n", data->dev);
+ fd = data->fd;
+ }
+ else
+ {
+ free (data->dev);
+ data->dev = 0;
+ if (GRUB_UTIL_FD_IS_VALID(data->fd))
+ {
+ if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
+ grub_util_fd_sync (data->fd);
+ grub_util_fd_close (data->fd);
+ data->fd = GRUB_UTIL_FD_INVALID;
+ }
+
+ fd = grub_util_fd_open (map[disk->id].device, flags);
+ if (GRUB_UTIL_FD_IS_VALID(fd))
+ {
+ data->dev = xstrdup (map[disk->id].device);
+ data->access_mode = (flags & O_ACCMODE);
+ data->fd = fd;
+ }
+ }
+
+ if (!GRUB_UTIL_FD_IS_VALID(data->fd))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+ map[disk->id].device, grub_util_fd_strerror ());
+ return GRUB_UTIL_FD_INVALID;
+ }
+
+ if (grub_util_fd_seek (fd, sector << disk->log_sector_size))
+ {
+ grub_util_fd_close (fd);
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
+ map[disk->id].device, grub_util_fd_strerror ());
+
+ return GRUB_UTIL_FD_INVALID;
+ }
+
+ return fd;
+}
+#endif
+
+
+static grub_err_t
+grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ while (size)
+ {
+ grub_util_fd_t fd;
+ grub_disk_addr_t max = ~0ULL;
+ fd = grub_util_fd_open_device (disk, sector, GRUB_UTIL_FD_O_RDONLY, &max);
+ if (!GRUB_UTIL_FD_IS_VALID (fd))
+ return grub_errno;
+
+#ifdef __linux__
+ if (sector == 0)
+ /* Work around a bug in Linux ez remapping. Linux remaps all
+ sectors that are read together with the MBR in one read. It
+ should only remap the MBR, so we split the read in two
+ parts. -jochen */
+ max = 1;
+#endif /* __linux__ */
+
+ if (max > size)
+ max = size;
+
+ if (grub_util_fd_read (fd, buf, max << disk->log_sector_size)
+ != (ssize_t) (max << disk->log_sector_size))
+ return grub_error (GRUB_ERR_READ_ERROR, N_("cannot read `%s': %s"),
+ map[disk->id].device, grub_util_fd_strerror ());
+ size -= max;
+ buf += (max << disk->log_sector_size);
+ sector += max;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, const char *buf)
+{
+ while (size)
+ {
+ grub_util_fd_t fd;
+ grub_disk_addr_t max = ~0ULL;
+ fd = grub_util_fd_open_device (disk, sector, GRUB_UTIL_FD_O_WRONLY, &max);
+ if (!GRUB_UTIL_FD_IS_VALID (fd))
+ return grub_errno;
+
+#ifdef __linux__
+ if (sector == 0)
+ /* Work around a bug in Linux ez remapping. Linux remaps all
+ sectors that are write together with the MBR in one write. It
+ should only remap the MBR, so we split the write in two
+ parts. -jochen */
+ max = 1;
+#endif /* __linux__ */
+
+ if (max > size)
+ max = size;
+
+ if (grub_util_fd_write (fd, buf, max << disk->log_sector_size)
+ != (ssize_t) (max << disk->log_sector_size))
+ return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write to `%s': %s"),
+ map[disk->id].device, grub_util_fd_strerror ());
+ size -= max;
+ buf += (max << disk->log_sector_size);
+ }
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_util_biosdisk_flush (struct grub_disk *disk)
+{
+ struct grub_util_hostdisk_data *data = disk->data;
+
+ if (disk->dev->id != GRUB_DISK_DEVICE_BIOSDISK_ID)
+ return GRUB_ERR_NONE;
+ if (!GRUB_UTIL_FD_IS_VALID (data->fd))
+ {
+ grub_disk_addr_t max;
+ data->fd = grub_util_fd_open_device (disk, 0, GRUB_UTIL_FD_O_RDONLY, &max);
+ if (!GRUB_UTIL_FD_IS_VALID (data->fd))
+ return grub_errno;
+ }
+ grub_util_fd_sync (data->fd);
+#ifdef __linux__
+ if (data->is_disk)
+ ioctl (data->fd, BLKFLSBUF, 0);
+#endif
+ return GRUB_ERR_NONE;
+}
+
+static void
+grub_util_biosdisk_close (struct grub_disk *disk)
+{
+ struct grub_util_hostdisk_data *data = disk->data;
+
+ free (data->dev);
+ if (GRUB_UTIL_FD_IS_VALID (data->fd))
+ {
+ if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
+ grub_util_biosdisk_flush (disk);
+ grub_util_fd_close (data->fd);
+ }
+ free (data);
+}
+
+static struct grub_disk_dev grub_util_biosdisk_dev =
+ {
+ .name = "hostdisk",
+ .id = GRUB_DISK_DEVICE_HOSTDISK_ID,
+ .disk_iterate = grub_util_biosdisk_iterate,
+ .disk_open = grub_util_biosdisk_open,
+ .disk_close = grub_util_biosdisk_close,
+ .disk_read = grub_util_biosdisk_read,
+ .disk_write = grub_util_biosdisk_write,
+ .next = 0
+ };
+
+static int
+grub_util_check_file_presence (const char *p)
+{
+#if !GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
+ grub_util_fd_t h;
+ h = grub_util_fd_open (p, GRUB_UTIL_FD_O_RDONLY);
+ if (!GRUB_UTIL_FD_IS_VALID(h))
+ return 0;
+ grub_util_fd_close (h);
+ return 1;
+#else
+ struct stat st;
+
+ if (stat (p, &st) == -1)
+ return 0;
+ return 1;
+#endif
+}
+
+static void
+read_device_map (const char *dev_map)
+{
+ FILE *fp;
+ char buf[1024]; /* XXX */
+ int lineno = 0;
+
+ if (!dev_map || dev_map[0] == '\0')
+ {
+ grub_util_info ("no device.map");
+ return;
+ }
+
+ fp = grub_util_fopen (dev_map, "r");
+ if (! fp)
+ {
+ grub_util_info (_("cannot open `%s': %s"), dev_map, strerror (errno));
+ return;
+ }
+
+ while (fgets (buf, sizeof (buf), fp))
+ {
+ char *p = buf;
+ char *e;
+ char *drive_e, *drive_p;
+ int drive;
+
+ lineno++;
+
+ /* Skip leading spaces. */
+ while (*p && grub_isspace (*p))
+ p++;
+
+ /* If the first character is `#' or NUL, skip this line. */
+ if (*p == '\0' || *p == '#')
+ continue;
+
+ if (*p != '(')
+ {
+ char *tmp;
+ tmp = xasprintf (_("missing `%c' symbol"), '(');
+ grub_util_error ("%s:%d: %s", dev_map, lineno, tmp);
+ }
+
+ p++;
+ /* Find a free slot. */
+ drive = find_free_slot ();
+ if (drive < 0)
+ grub_util_error ("%s:%d: %s", dev_map, lineno, _("device count exceeds limit"));
+
+ e = p;
+ p = strchr (p, ')');
+ if (! p)
+ {
+ char *tmp;
+ tmp = xasprintf (_("missing `%c' symbol"), ')');
+ grub_util_error ("%s:%d: %s", dev_map, lineno, tmp);
+ }
+
+ map[drive].drive = 0;
+ if ((e[0] == 'f' || e[0] == 'h' || e[0] == 'c') && e[1] == 'd')
+ {
+ char *ptr;
+ for (ptr = e + 2; ptr < p; ptr++)
+ if (!grub_isdigit (*ptr))
+ break;
+ if (ptr == p)
+ {
+ map[drive].drive = xmalloc (p - e + sizeof ('\0'));
+ strncpy (map[drive].drive, e, p - e + sizeof ('\0'));
+ map[drive].drive[p - e] = '\0';
+ }
+ if (*ptr == ',')
+ {
+ *p = 0;
+
+ /* TRANSLATORS: Only one entry is ignored. However the suggestion
+ is to correct/delete the whole file.
+ device.map is a file indicating which
+ devices are available at boot time. Fedora populated it with
+ entries like (hd0,1) /dev/sda1 which would mean that every
+ partition is a separate disk for BIOS. Such entries were
+ inactive in GRUB due to its bug which is now gone. Without
+ this additional check these entries would be harmful now.
+ */
+ grub_util_warn (_("the device.map entry `%s' is invalid. "
+ "Ignoring it. Please correct or "
+ "delete your device.map"), e);
+ continue;
+ }
+ }
+ drive_e = e;
+ drive_p = p;
+ map[drive].device_map = 1;
+
+ p++;
+ /* Skip leading spaces. */
+ while (*p && grub_isspace (*p))
+ p++;
+
+ if (*p == '\0')
+ grub_util_error ("%s:%d: %s", dev_map, lineno, _("filename expected"));
+
+ /* NUL-terminate the filename. */
+ e = p;
+ while (*e && ! grub_isspace (*e))
+ e++;
+ *e = '\0';
+
+ if (!grub_util_check_file_presence (p))
+ {
+ free (map[drive].drive);
+ map[drive].drive = NULL;
+ grub_util_info ("Cannot stat `%s', skipping", p);
+ continue;
+ }
+
+ /* On Linux, the devfs uses symbolic links horribly, and that
+ confuses the interface very much, so use realpath to expand
+ symbolic links. */
+ map[drive].device = grub_canonicalize_file_name (p);
+ if (! map[drive].device)
+ map[drive].device = xstrdup (p);
+
+ if (!map[drive].drive)
+ {
+ char c;
+ map[drive].drive = xmalloc (sizeof ("hostdisk/") + strlen (p));
+ memcpy (map[drive].drive, "hostdisk/", sizeof ("hostdisk/") - 1);
+ strcpy (map[drive].drive + sizeof ("hostdisk/") - 1, p);
+ c = *drive_p;
+ *drive_p = 0;
+ /* TRANSLATORS: device.map is a filename. Not to be translated.
+ device.map specifies disk correspondance overrides. Previously
+ one could create any kind of device name with this. Due to
+ some problems we decided to limit it to just a handful
+ possibilities. */
+ grub_util_warn (_("the drive name `%s' in device.map is incorrect. "
+ "Using %s instead. "
+ "Please use the form [hfc]d[0-9]* "
+ "(E.g. `hd0' or `cd')"),
+ drive_e, map[drive].drive);
+ *drive_p = c;
+ }
+
+ grub_util_info ("adding `%s' -> `%s' from device.map", map[drive].drive,
+ map[drive].device);
+
+ grub_hostdisk_flush_initial_buffer (map[drive].device);
+ }
+
+ fclose (fp);
+}
+
+void
+grub_util_biosdisk_init (const char *dev_map)
+{
+ read_device_map (dev_map);
+ grub_disk_dev_register (&grub_util_biosdisk_dev);
+}
+
+void
+grub_util_biosdisk_fini (void)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(map); i++)
+ {
+ if (map[i].drive)
+ free (map[i].drive);
+ if (map[i].device)
+ free (map[i].device);
+ map[i].drive = map[i].device = NULL;
+ }
+
+ grub_disk_dev_unregister (&grub_util_biosdisk_dev);
+}
+
+const char *
+grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
+{
+ if (disk->dev != &grub_util_biosdisk_dev || map[disk->id].device_map)
+ return disk->name;
+ return 0;
+}
+
+const char *
+grub_util_biosdisk_get_osdev (grub_disk_t disk)
+{
+ if (disk->dev != &grub_util_biosdisk_dev)
+ return 0;
+
+ return map[disk->id].device;
+}
+
+
+static char *
+grub_util_path_concat_real (size_t n, int ext, va_list ap)
+{
+ size_t totlen = 0;
+ char **l = xcalloc (n + ext, sizeof (l[0]));
+ char *r, *p, *pi;
+ size_t i;
+ int first = 1;
+
+ for (i = 0; i < n + ext; i++)
+ {
+ l[i] = va_arg (ap, char *);
+ if (l[i])
+ totlen += strlen (l[i]) + 1;
+ }
+
+ r = xmalloc (totlen + 10);
+
+ p = r;
+ for (i = 0; i < n; i++)
+ {
+ pi = l[i];
+ if (!pi)
+ continue;
+ while (*pi == '/')
+ pi++;
+ if ((p != r || (pi != l[i] && first)) && (p == r || *(p - 1) != '/'))
+ *p++ = '/';
+ first = 0;
+ p = grub_stpcpy (p, pi);
+ while (p != r && p != r + 1 && *(p - 1) == '/')
+ p--;
+ }
+
+ if (ext && l[i])
+ p = grub_stpcpy (p, l[i]);
+
+ *p = '\0';
+
+ free (l);
+
+ return r;
+}
+
+char *
+grub_util_path_concat (size_t n, ...)
+{
+ va_list ap;
+ char *r;
+
+ va_start (ap, n);
+
+ r = grub_util_path_concat_real (n, 0, ap);
+
+ va_end (ap);
+
+ return r;
+}
+
+char *
+grub_util_path_concat_ext (size_t n, ...)
+{
+ va_list ap;
+ char *r;
+
+ va_start (ap, n);
+
+ r = grub_util_path_concat_real (n, 1, ap);
+
+ va_end (ap);
+
+ return r;
+}
diff --git a/grub-core/kern/emu/hostfs.c b/grub-core/kern/emu/hostfs.c
new file mode 100644
index 0000000..cb53210
--- /dev/null
+++ b/grub-core/kern/emu/hostfs.c
@@ -0,0 +1,200 @@
+/* hostfs.c - Dummy filesystem to provide access to the hosts filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/fs.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/util/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/i18n.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+static int
+is_dir (const char *path, const char *name)
+{
+ int len1 = strlen(path);
+ int len2 = strlen(name);
+ int ret;
+
+ char *pathname = xmalloc (len1 + 1 + len2 + 1 + 13);
+ strcpy (pathname, path);
+
+ /* Avoid UNC-path "//name" on Cygwin. */
+ if (len1 > 0 && pathname[len1 - 1] != '/')
+ strcat (pathname, "/");
+
+ strcat (pathname, name);
+
+ ret = grub_util_is_directory (pathname);
+ free (pathname);
+ return ret;
+}
+
+struct grub_hostfs_data
+{
+ char *filename;
+ grub_util_fd_t f;
+};
+
+static grub_err_t
+grub_hostfs_dir (grub_device_t device, const char *path,
+ grub_fs_dir_hook_t hook, void *hook_data)
+{
+ grub_util_fd_dir_t dir;
+
+ /* Check if the disk is our dummy disk. */
+ if (grub_strcmp (device->disk->name, "host"))
+ return grub_error (GRUB_ERR_BAD_FS, "not a hostfs");
+
+ dir = grub_util_fd_opendir (path);
+ if (! dir)
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("can't open `%s': %s"), path,
+ grub_util_fd_strerror ());
+
+ while (1)
+ {
+ grub_util_fd_dirent_t de;
+ struct grub_dirhook_info info;
+ grub_memset (&info, 0, sizeof (info));
+
+ de = grub_util_fd_readdir (dir);
+ if (! de)
+ break;
+
+ info.dir = !! is_dir (path, de->d_name);
+ hook (de->d_name, &info, hook_data);
+
+ }
+
+ grub_util_fd_closedir (dir);
+
+ return GRUB_ERR_NONE;
+}
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_hostfs_open (struct grub_file *file, const char *name)
+{
+ grub_util_fd_t f;
+ struct grub_hostfs_data *data;
+
+ f = grub_util_fd_open (name, GRUB_UTIL_FD_O_RDONLY);
+ if (! GRUB_UTIL_FD_IS_VALID (f))
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("can't open `%s': %s"), name,
+ strerror (errno));
+ data = grub_malloc (sizeof (*data));
+ if (!data)
+ {
+ grub_util_fd_close (f);
+ return grub_errno;
+ }
+ data->filename = grub_strdup (name);
+ if (!data->filename)
+ {
+ grub_free (data);
+ grub_util_fd_close (f);
+ return grub_errno;
+ }
+
+ data->f = f;
+
+ file->data = data;
+
+ file->size = grub_util_get_fd_size (f, name, NULL);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_ssize_t
+grub_hostfs_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_hostfs_data *data;
+
+ data = file->data;
+ if (grub_util_fd_seek (data->f, file->offset) != 0)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("cannot seek `%s': %s"),
+ data->filename, grub_util_fd_strerror ());
+ return -1;
+ }
+
+ unsigned int s = grub_util_fd_read (data->f, buf, len);
+ if (s != len)
+ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("cannot read `%s': %s"),
+ data->filename, grub_util_fd_strerror ());
+
+ return (signed) s;
+}
+
+static grub_err_t
+grub_hostfs_close (grub_file_t file)
+{
+ struct grub_hostfs_data *data;
+
+ data = file->data;
+ grub_util_fd_close (data->f);
+ grub_free (data->filename);
+ grub_free (data);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_hostfs_label (grub_device_t device __attribute ((unused)),
+ char **label __attribute ((unused)))
+{
+ *label = 0;
+ return GRUB_ERR_NONE;
+}
+
+#undef open
+#undef close
+
+static struct grub_fs grub_hostfs_fs =
+ {
+ .name = "hostfs",
+ .fs_dir = grub_hostfs_dir,
+ .fs_open = grub_hostfs_open,
+ .fs_read = grub_hostfs_read,
+ .fs_close = grub_hostfs_close,
+ .fs_label = grub_hostfs_label,
+ .next = 0
+ };
+
+
+
+GRUB_MOD_INIT(hostfs)
+{
+ grub_fs_register (&grub_hostfs_fs);
+}
+
+GRUB_MOD_FINI(hostfs)
+{
+ grub_fs_unregister (&grub_hostfs_fs);
+}
diff --git a/grub-core/kern/emu/lite.c b/grub-core/kern/emu/lite.c
new file mode 100644
index 0000000..b327d4e
--- /dev/null
+++ b/grub-core/kern/emu/lite.c
@@ -0,0 +1,47 @@
+#include <config.h>
+#include <grub/emu/misc.h>
+
+#ifndef GRUB_MACHINE_EMU
+#error "This source is only meant for grub-emu platform"
+#endif
+
+#if defined(__i386__)
+#include "../i386/dl.c"
+#elif defined(__x86_64__)
+#include "../x86_64/dl.c"
+#elif defined(__sparc__)
+#include "../sparc64/dl.c"
+#elif defined(__mips__)
+#include "../mips/dl.c"
+#elif defined(__powerpc__)
+#include "../powerpc/dl.c"
+#elif defined(__ia64__)
+#include "../ia64/dl_helper.c"
+#include "../ia64/dl.c"
+#elif defined(__arm__)
+#include "../arm/dl_helper.c"
+#include "../arm/dl.c"
+#elif defined(__aarch64__)
+#include "../arm64/dl_helper.c"
+#include "../arm64/dl.c"
+#elif defined(__riscv)
+#include "../riscv/dl.c"
+#else
+#error "No target cpu type is defined"
+#endif
+
+const int grub_no_modules = 0;
+
+/* grub-emu-lite supports dynamic module loading, so it won't have any
+ embedded modules. */
+void
+grub_init_all (void)
+{
+ return;
+}
+
+void
+grub_fini_all (void)
+{
+ return;
+}
diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
new file mode 100644
index 0000000..425bb96
--- /dev/null
+++ b/grub-core/kern/emu/main.c
@@ -0,0 +1,286 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/setjmp.h>
+#include <grub/fs.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/time.h>
+#include <grub/emu/console.h>
+#include <grub/emu/misc.h>
+#include <grub/kernel.h>
+#include <grub/normal.h>
+#include <grub/emu/getroot.h>
+#include <grub/env.h>
+#include <grub/partition.h>
+#include <grub/i18n.h>
+#include <grub/loader.h>
+#include <grub/util/misc.h>
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+#include "progname.h"
+#include <argp.h>
+
+#define ENABLE_RELOCATABLE 0
+
+/* Used for going back to the main function. */
+static jmp_buf main_env;
+
+/* Store the prefix specified by an argument. */
+static char *root_dev = NULL, *dir = NULL;
+
+grub_addr_t grub_modbase = 0;
+
+void
+grub_reboot (void)
+{
+ longjmp (main_env, 1);
+ grub_fatal ("longjmp failed");
+}
+
+void
+grub_exit (void)
+{
+ grub_reboot ();
+}
+
+void
+grub_machine_init (void)
+{
+}
+
+void
+grub_machine_get_bootlocation (char **device, char **path)
+{
+ *device = root_dev;
+ *path = dir;
+}
+
+void
+grub_machine_fini (int flags)
+{
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_console_fini ();
+}
+
+
+
+#define OPT_MEMDISK 257
+
+static struct argp_option options[] = {
+ {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2},
+ {"device-map", 'm', N_("FILE"), 0,
+ /* TRANSLATORS: There are many devices in device map. */
+ N_("use FILE as the device map [default=%s]"), 0},
+ {"memdisk", OPT_MEMDISK, N_("FILE"), 0,
+ /* TRANSLATORS: There are many devices in device map. */
+ N_("use FILE as memdisk"), 0},
+ {"directory", 'd', N_("DIR"), 0,
+ N_("use GRUB files in the directory DIR [default=%s]"), 0},
+ {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
+ {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+static char *
+help_filter (int key, const char *text, void *input __attribute__ ((unused)))
+{
+ switch (key)
+ {
+ case 'd':
+ return xasprintf (text, DEFAULT_DIRECTORY);
+ case 'm':
+ return xasprintf (text, DEFAULT_DEVICE_MAP);
+ default:
+ return (char *) text;
+ }
+}
+
+#pragma GCC diagnostic error "-Wformat-nonliteral"
+
+struct arguments
+{
+ const char *dev_map;
+ const char *mem_disk;
+ int hold;
+};
+
+static error_t
+argp_parser (int key, char *arg, struct argp_state *state)
+{
+ /* Get the input argument from argp_parse, which we
+ know is a pointer to our arguments structure. */
+ struct arguments *arguments = state->input;
+
+ switch (key)
+ {
+ case OPT_MEMDISK:
+ arguments->mem_disk = arg;
+ break;
+ case 'r':
+ free (root_dev);
+ root_dev = xstrdup (arg);
+ break;
+ case 'd':
+ free (dir);
+ dir = xstrdup (arg);
+ break;
+ case 'm':
+ arguments->dev_map = arg;
+ break;
+ case 'H':
+ arguments->hold = (arg ? atoi (arg) : -1);
+ break;
+ case 'v':
+ verbosity++;
+ break;
+
+ case ARGP_KEY_ARG:
+ {
+ /* Too many arguments. */
+ fprintf (stderr, _("Unknown extra argument `%s'."), arg);
+ fprintf (stderr, "\n");
+ argp_usage (state);
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = {
+ options, argp_parser, NULL,
+ N_("GRUB emulator."),
+ NULL, help_filter, NULL
+};
+
+
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+
+int
+main (int argc, char *argv[])
+{
+ struct arguments arguments =
+ {
+ .dev_map = DEFAULT_DEVICE_MAP,
+ .hold = 0,
+ .mem_disk = 0,
+ };
+ volatile int hold = 0;
+ size_t total_module_size = sizeof (struct grub_module_info), memdisk_size = 0;
+ struct grub_module_info *modinfo;
+ void *mods;
+
+ grub_util_host_init (&argc, &argv);
+
+ dir = xstrdup (DEFAULT_DIRECTORY);
+
+ if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
+ {
+ fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
+ exit(1);
+ }
+
+ if (arguments.mem_disk)
+ {
+ memdisk_size = ALIGN_UP(grub_util_get_image_size (arguments.mem_disk), 512);
+ total_module_size += memdisk_size + sizeof (struct grub_module_header);
+ }
+
+ mods = xmalloc (total_module_size);
+ modinfo = grub_memset (mods, 0, total_module_size);
+ mods = (char *) (modinfo + 1);
+
+ modinfo->magic = GRUB_MODULE_MAGIC;
+ modinfo->offset = sizeof (struct grub_module_info);
+ modinfo->size = total_module_size;
+
+ if (arguments.mem_disk)
+ {
+ struct grub_module_header *header = (struct grub_module_header *) mods;
+ header->type = OBJ_TYPE_MEMDISK;
+ header->size = memdisk_size + sizeof (*header);
+ mods = header + 1;
+
+ grub_util_load_image (arguments.mem_disk, mods);
+ mods = (char *) mods + memdisk_size;
+ }
+
+ grub_modbase = (grub_addr_t) modinfo;
+
+ hold = arguments.hold;
+ /* Wait until the ARGS.HOLD variable is cleared by an attached debugger. */
+ if (hold && verbosity > 0)
+ /* TRANSLATORS: In this case GRUB tells user what he has to do. */
+ printf (_("Run `gdb %s %d', and set ARGS.HOLD to zero.\n"),
+ program_name, (int) getpid ());
+ while (hold)
+ {
+ if (hold > 0)
+ hold--;
+
+ sleep (1);
+ }
+
+ signal (SIGINT, SIG_IGN);
+ grub_console_init ();
+ grub_host_init ();
+
+ /* XXX: This is a bit unportable. */
+ grub_util_biosdisk_init (arguments.dev_map);
+
+ grub_init_all ();
+
+ grub_hostfs_init ();
+
+ /* Make sure that there is a root device. */
+ if (! root_dev)
+ root_dev = grub_strdup ("host");
+
+ dir = xstrdup (dir);
+
+ /* Start GRUB! */
+ if (setjmp (main_env) == 0)
+ grub_main ();
+
+ grub_fini_all ();
+ grub_hostfs_fini ();
+ grub_host_fini ();
+
+ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
+
+ return 0;
+}
diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
new file mode 100644
index 0000000..dfd8a8e
--- /dev/null
+++ b/grub-core/kern/emu/misc.c
@@ -0,0 +1,216 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_BUILD
+#include <config-util.h>
+#endif
+#include <config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/time.h>
+#include <grub/emu/misc.h>
+
+int verbosity;
+
+void
+grub_util_warn (const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf (stderr, _("%s: warning:"), program_name);
+ fprintf (stderr, " ");
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fprintf (stderr, ".\n");
+ fflush (stderr);
+}
+
+void
+grub_util_info (const char *fmt, ...)
+{
+ if (verbosity > 0)
+ {
+ va_list ap;
+
+ fprintf (stderr, _("%s: info:"), program_name);
+ fprintf (stderr, " ");
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fprintf (stderr, ".\n");
+ fflush (stderr);
+ }
+}
+
+void
+grub_util_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf (stderr, _("%s: error:"), program_name);
+ fprintf (stderr, " ");
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fprintf (stderr, ".\n");
+ exit (1);
+}
+
+void *
+xcalloc (grub_size_t nmemb, grub_size_t size)
+{
+ void *p;
+
+ p = calloc (nmemb, size);
+ if (!p)
+ grub_util_error ("%s", _("out of memory"));
+
+ return p;
+}
+
+void *
+xmalloc (grub_size_t size)
+{
+ void *p;
+
+ p = malloc (size);
+ if (! p)
+ grub_util_error ("%s", _("out of memory"));
+
+ return p;
+}
+
+void *
+xrealloc (void *ptr, grub_size_t size)
+{
+ ptr = realloc (ptr, size);
+ if (! ptr)
+ grub_util_error ("%s", _("out of memory"));
+
+ return ptr;
+}
+
+char *
+xstrdup (const char *str)
+{
+ size_t len;
+ char *newstr;
+
+ len = strlen (str);
+ newstr = (char *) xmalloc (len + 1);
+ memcpy (newstr, str, len + 1);
+
+ return newstr;
+}
+
+#if !defined (GRUB_MKFONT) && !defined (GRUB_BUILD)
+char *
+xasprintf (const char *fmt, ...)
+{
+ va_list ap;
+ char *result;
+
+ va_start (ap, fmt);
+ result = grub_xvasprintf (fmt, ap);
+ va_end (ap);
+ if (!result)
+ grub_util_error ("%s", _("out of memory"));
+
+ return result;
+}
+#endif
+
+#if !defined (GRUB_MACHINE_EMU) || defined (GRUB_UTIL)
+void
+grub_exit (void)
+{
+ exit (1);
+}
+#endif
+
+grub_uint64_t
+grub_get_time_ms (void)
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, 0);
+
+ return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+}
+
+size_t
+grub_util_get_image_size (const char *path)
+{
+ FILE *f;
+ size_t ret;
+ off_t sz;
+
+ f = grub_util_fopen (path, "rb");
+
+ if (!f)
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ fseeko (f, 0, SEEK_END);
+
+ sz = ftello (f);
+ if (sz < 0)
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+ if (sz != (size_t) sz)
+ grub_util_error (_("file `%s' is too big"), path);
+ ret = (size_t) sz;
+
+ fclose (f);
+
+ return ret;
+}
+
+void
+grub_util_load_image (const char *path, char *buf)
+{
+ FILE *fp;
+ size_t size;
+
+ grub_util_info ("reading %s", path);
+
+ size = grub_util_get_image_size (path);
+
+ fp = grub_util_fopen (path, "rb");
+ if (! fp)
+ grub_util_error (_("cannot open `%s': %s"), path,
+ strerror (errno));
+
+ if (fread (buf, 1, size, fp) != size)
+ grub_util_error (_("cannot read `%s': %s"), path,
+ strerror (errno));
+
+ fclose (fp);
+}
diff --git a/grub-core/kern/emu/mm.c b/grub-core/kern/emu/mm.c
new file mode 100644
index 0000000..4d1046a
--- /dev/null
+++ b/grub-core/kern/emu/mm.c
@@ -0,0 +1,75 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grub/i18n.h>
+
+void *
+grub_calloc (grub_size_t nmemb, grub_size_t size)
+{
+ void *ret;
+ ret = calloc (nmemb, size);
+ if (!ret)
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return ret;
+}
+
+void *
+grub_malloc (grub_size_t size)
+{
+ void *ret;
+ ret = malloc (size);
+ if (!ret)
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return ret;
+}
+
+void *
+grub_zalloc (grub_size_t size)
+{
+ void *ret;
+
+ ret = grub_malloc (size);
+ if (!ret)
+ return NULL;
+ memset (ret, 0, size);
+ return ret;
+}
+
+void
+grub_free (void *ptr)
+{
+ if (ptr)
+ free (ptr);
+}
+
+void *
+grub_realloc (void *ptr, grub_size_t size)
+{
+ void *ret;
+ ret = realloc (ptr, size);
+ if (!ret)
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return ret;
+}
diff --git a/grub-core/kern/emu/time.c b/grub-core/kern/emu/time.c
new file mode 100644
index 0000000..5da8092
--- /dev/null
+++ b/grub-core/kern/emu/time.c
@@ -0,0 +1,46 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/datetime.h>
+#include <time.h>
+
+grub_err_t
+grub_get_datetime (struct grub_datetime *datetime)
+{
+ struct tm *mytm;
+ time_t mytime;
+
+ mytime = time (&mytime);
+ mytm = gmtime (&mytime);
+
+ datetime->year = mytm->tm_year + 1900;
+ datetime->month = mytm->tm_mon + 1;
+ datetime->day = mytm->tm_mday;
+ datetime->hour = mytm->tm_hour;
+ datetime->minute = mytm->tm_min;
+ datetime->second = mytm->tm_sec;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_set_datetime (struct grub_datetime *datetime __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "no clock setting routine available");
+}