XEN PV environment and load kernels.
+2013-11-09 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Add new ports: i386-xen and x86_64-xen. This allows running GRUB in
+ XEN PV environment and load kernels.
+
2013-11-09 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/i386/multiboot_mbi.c: Handle space in command line.
LDFLAGS_PLATFORM = -Wl,--wrap=__clear_cache
endif
+#FIXME: discover and check XEN headers
+CPPFLAGS_XEN = -I/usr/include
+
# Other options
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\"
case "$target_cpu"-"$platform" in
x86_64-efi) ;;
x86_64-emu) ;;
+ x86_64-xen) ;;
x86_64-*) target_cpu=i386 ;;
powerpc64-ieee1275) target_cpu=powerpc ;;
esac
case "$target_cpu"-"$platform" in
i386-efi) ;;
x86_64-efi) ;;
+ i386-xen) ;;
+ x86_64-xen) ;;
i386-pc) ;;
i386-multiboot) ;;
i386-coreboot) ;;
coreboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_COREBOOT=1" ;;
multiboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MULTIBOOT=1" ;;
efi) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EFI=1" ;;
+ xen) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_XEN=1" ;;
ieee1275) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_IEEE1275=1" ;;
uboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_UBOOT=1" ;;
qemu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_QEMU=1" ;;
AM_CONDITIONAL([COND_i386_coreboot], [test x$target_cpu = xi386 -a x$platform = xcoreboot])
AM_CONDITIONAL([COND_i386_multiboot], [test x$target_cpu = xi386 -a x$platform = xmultiboot])
AM_CONDITIONAL([COND_x86_64_efi], [test x$target_cpu = xx86_64 -a x$platform = xefi])
+AM_CONDITIONAL([COND_i386_xen], [test x$target_cpu = xi386 -a x$platform = xxen])
+AM_CONDITIONAL([COND_x86_64_xen], [test x$target_cpu = xx86_64 -a x$platform = xxen])
AM_CONDITIONAL([COND_mips_loongson], [test x$target_cpu = xmipsel -a x$platform = xloongson])
AM_CONDITIONAL([COND_mips_qemu_mips], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")" -a x$platform = xqemu_mips])
AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")" -a x$platform = xarc])
Lightly limited platforms:
@itemize
+@item *-xen: limited only by adress space and RAM size.
@item i386-qemu: kernel.img (.text + .data + .bss) is limited by 392704 bytes.
(core.img would be limited by ROM size but it's unlimited on qemu
@item All EFI platforms: limited by contiguous RAM size and possibly firmware bugs
AHCI, PATA (ata), crypto, USB use the name of driver followed by a number.
Memdisk and host are limited to one disk and so it's refered just by driver
name.
-RAID (md), ofdisk (ieee1275 and nand), LVM (lvm), LDM and arcdisk (arc) use
-intrinsic name of disk prefixed by driver name. Additionally just ``nand''
-refers to the disk aliased as ``nand''.
+RAID (md), ofdisk (ieee1275 and nand), LVM (lvm), LDM, virtio (vdsk)
+and arcdisk (arc) use intrinsic name of disk prefixed by driver name.
+Additionally just ``nand'' refers to the disk aliased as ``nand''.
Conflicts are solved by suffixing a number if necessarry.
Commas need to be escaped.
Loopback uses whatever name specified to @command{loopback} command.
GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"i386_multiboot", "i386_ieee1275", "x86_64_efi",
+ "i386_xen", "x86_64_xen",
"mips_loongson", "sparc64_ieee1275",
"powerpc_ieee1275", "mips_arc", "ia64_efi",
"mips_qemu_mips", "arm_uboot", "arm_efi" ]
GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi" ]
GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
GROUPS["uboot"] = [ "arm_uboot" ]
+GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ]
# emu is a special case so many core functionality isn't needed on this platform
GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu")
# Groups based on hardware features
GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips",
"sparc64_ieee1275", "powerpc_ieee1275"]
-GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi")
+GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi");
GROUPS["pci"] = GROUPS["x86"] + ["mips_loongson"]
GROUPS["usb"] = GROUPS["pci"]
for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
# Similar for terminfo
-GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["ieee1275"] + GROUPS["uboot"];
+GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips" ] + GROUPS["xen"] + GROUPS["ieee1275"] + GROUPS["uboot"];
GROUPS["terminfomodule"] = GRUB_PLATFORMS[:];
for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
endif
+if COND_i386_xen
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/xen/hypercall.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h
+endif
+
+if COND_x86_64_xen
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/x86_64/xen/hypercall.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h
+endif
+
if COND_x86_64_efi
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
ia64_efi_ldflags = '-Wl,-r,-d';
ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+ x86_64_xen_ldflags = '-Wl,-Ttext=0';
+ x86_64_xen_cppflags = '$(CPPFLAGS_XEN)';
+ i386_xen_ldflags = '-Wl,-Ttext=0';
+ i386_xen_cppflags = '$(CPPFLAGS_XEN)';
+
arm_efi_ldflags = '-Wl,-r,-d';
arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
i386_pc_startup = kern/i386/pc/startup.S;
i386_efi_startup = kern/i386/efi/startup.S;
x86_64_efi_startup = kern/x86_64/efi/startup.S;
+ i386_xen_startup = kern/i386/xen/startup.S;
+ x86_64_xen_startup = kern/x86_64/xen/startup.S;
i386_qemu_startup = kern/i386/qemu/startup.S;
i386_ieee1275_startup = kern/i386/ieee1275/startup.S;
i386_coreboot_startup = kern/i386/coreboot/startup.S;
terminfoinkernel = lib/arg.c;
i386 = kern/i386/dl.c;
+ i386_xen = kern/i386/dl.c;
i386_coreboot = kern/i386/coreboot/init.c;
i386_multiboot = kern/i386/coreboot/init.c;
i386_efi = kern/i386/efi/init.c;
i386_efi = bus/pci.c;
- x86_64_efi = kern/x86_64/dl.c;
+ x86_64 = kern/x86_64/dl.c;
+ x86_64_xen = kern/x86_64/dl.c;
x86_64_efi = kern/x86_64/efi/callwrap.S;
x86_64_efi = kern/i386/efi/init.c;
x86_64_efi = bus/pci.c;
+ xen = kern/i386/tsc.c;
+ x86_64_xen = kern/x86_64/xen/hypercall.S;
+ i386_xen = kern/i386/xen/hypercall.S;
+ xen = kern/xen/init.c;
+ xen = term/xen/console.c;
+ xen = disk/xen/xendisk.c;
+ xen = commands/boot.c;
+
ia64_efi = kern/ia64/efi/startup.S;
ia64_efi = kern/ia64/efi/init.c;
ia64_efi = kern/ia64/dl.c;
enable = mips_arc;
};
+module = {
+ name = lsxen;
+ common = commands/xen/lsxen.c;
+ cppflags = '$(CPPFLAGS_XEN)';
+
+ enable = xen;
+};
+
module = {
name = check_nt_hiberfil;
common = commands/i386/nthibr.c;
module = {
name = cpuid;
- x86 = commands/i386/cpuid.c;
+ common = commands/i386/cpuid.c;
enable = x86;
+ enable = i386_xen;
+ enable = x86_64_xen;
};
module = {
i386_multiboot = lib/i386/halt.c;
i386_coreboot = lib/i386/halt.c;
i386_qemu = lib/i386/halt.c;
+ xen = lib/xen/halt.c;
+ xen_cppflags = '$(CPPFLAGS_XEN)';
efi = lib/efi/halt.c;
ieee1275 = lib/ieee1275/halt.c;
emu = lib/emu/halt.c;
mips_arc = lib/mips/arc/reboot.c;
mips_loongson = lib/mips/loongson/reboot.c;
mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
+ xen = lib/xen/reboot.c;
+ xen_cppflags = '$(CPPFLAGS_XEN)';
uboot = lib/uboot/reboot.c;
common = commands/reboot.c;
};
common = io/gzio.c;
};
+module = {
+ name = offsetio;
+ common = io/offset.c;
+};
+
module = {
name = bufio;
common = io/bufio.c;
x86 = lib/i386/relocator64.S;
i386 = lib/i386/relocator_asm.S;
x86_64 = lib/x86_64/relocator_asm.S;
+ i386_xen = lib/i386/relocator_asm.S;
+ x86_64_xen = lib/x86_64/relocator_asm.S;
x86 = lib/i386/relocator.c;
+ x86 = lib/i386/relocator_common_c.c;
ieee1275 = lib/ieee1275/relocator.c;
efi = lib/efi/relocator.c;
mips = lib/mips/relocator_asm.S;
mips = lib/mips/relocator.c;
powerpc = lib/powerpc/relocator_asm.S;
powerpc = lib/powerpc/relocator.c;
+ xen = lib/xen/relocator.c;
+ i386_xen = lib/i386/xen/relocator.S;
+ x86_64_xen = lib/x86_64/xen/relocator.S;
+ xen = lib/i386/relocator_common_c.c;
+ xen_cppflags = '$(CPPFLAGS_XEN)';
extra_dist = lib/i386/relocator_common.S;
extra_dist = kern/powerpc/cache_flush.S;
enable = mips;
enable = powerpc;
enable = x86;
+ enable = xen;
};
module = {
powerpc_ieee1275 = lib/ieee1275/datetime.c;
sparc64_ieee1275 = lib/ieee1275/cmos.c;
powerpc_ieee1275 = lib/ieee1275/cmos.c;
+ xen = lib/xen/datetime.c;
+ xen_cppflags = '$(CPPFLAGS_XEN)';
mips_arc = lib/arc/datetime.c;
enable = noemu;
module = {
name = linux;
x86 = loader/i386/linux.c;
+ xen = loader/i386/xen.c;
+ xen = loader/i386/xen_file.c;
+ xen = loader/i386/xen_file32.c;
+ xen = loader/i386/xen_file64.c;
+ extra_dist = loader/i386/xen_fileXX.c;
+ xen_cppflags = '$(CPPFLAGS_XEN)';
i386_pc = lib/i386/pc/vesa_modes_table.c;
mips = loader/mips/linux.c;
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
emu = lib/i386/pc/vesa_modes_table.c;
i386_efi = lib/i386/pc/vesa_modes_table.c;
x86_64_efi = lib/i386/pc/vesa_modes_table.c;
+ xen = lib/i386/pc/vesa_modes_table.c;
enable = i386_pc;
enable = i386_efi;
enable = x86_64_efi;
enable = emu;
+ enable = xen;
};
module = {
module = {
name = backtrace;
x86 = lib/i386/backtrace.c;
+ i386_xen = lib/i386/backtrace.c;
+ x86_64_xen = lib/i386/backtrace.c;
common = lib/backtrace.c;
enable = x86;
+ enable = i386_xen;
+ enable = x86_64_xen;
};
module = {
return grub_error (GRUB_ERR_NO_KERNEL,
N_("you need to load the kernel first"));
- if (grub_loader_flags & GRUB_LOADER_FLAG_NORETURN)
- grub_machine_fini ();
+ grub_machine_fini (grub_loader_flags);
for (cur = preboots_head; cur; cur = cur->next)
{
/* Native disks. */
case GRUB_DISK_DEVICE_ATA_ID:
case GRUB_DISK_DEVICE_SCSI_ID:
+ case GRUB_DISK_DEVICE_XEN:
if (getnative)
break;
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/dl.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/xen.h>
+#include <grub/term.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static int
+hook (const char *dir, void *hook_data __attribute__ ((unused)))
+{
+ grub_printf ("%s\n", dir);
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_lsxen (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char *dir;
+ grub_err_t err;
+ char *buf;
+
+ if (argc >= 1)
+ return grub_xenstore_dir (args[0], hook, NULL);
+
+ buf = grub_xenstore_get_file ("domid", NULL);
+ if (!buf)
+ return grub_errno;
+ dir = grub_xasprintf ("/local/domain/%s", buf);
+ grub_free (buf);
+ err = grub_xenstore_dir (dir, hook, NULL);
+ grub_free (dir);
+ return err;
+}
+
+static grub_err_t
+grub_cmd_catxen (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ const char *dir = "domid";
+ char *buf;
+
+ if (argc >= 1)
+ dir = args[0];
+
+ buf = grub_xenstore_get_file (dir, NULL);
+ if (!buf)
+ return grub_errno;
+ grub_xputs (buf);
+ grub_xputs ("\n");
+ grub_free (buf);
+ return GRUB_ERR_NONE;
+
+}
+
+static grub_command_t cmd_ls, cmd_cat;
+
+GRUB_MOD_INIT (lsxen)
+{
+ cmd_ls = grub_register_command ("xen_ls", grub_cmd_lsxen, "[DIR]",
+ N_("List XEN storage."));
+ cmd_cat = grub_register_command ("xen_cat", grub_cmd_catxen, "[DIR]",
+ N_("List XEN storage."));
+}
+
+GRUB_MOD_FINI (lsxen)
+{
+ grub_unregister_command (cmd_ls);
+ grub_unregister_command (cmd_cat);
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/disk.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/term.h>
+#include <grub/i18n.h>
+#include <grub/xen.h>
+#include <grub/time.h>
+#include <xen/io/blkif.h>
+
+struct virtdisk
+{
+ int handle;
+ char *fullname;
+ char *backend_dir;
+ char *frontend_dir;
+ struct blkif_sring *shared_page;
+ struct blkif_front_ring ring;
+ grub_xen_grant_t grant;
+ grub_xen_evtchn_t evtchn;
+ void *dma_page;
+ grub_xen_grant_t dma_grant;
+};
+
+#define xen_wmb() mb()
+#define xen_mb() mb()
+
+static struct virtdisk *virtdisks;
+static grub_size_t vdiskcnt;
+
+static int
+grub_virtdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
+ grub_disk_pull_t pull)
+{
+ grub_size_t i;
+
+ if (pull != GRUB_DISK_PULL_NONE)
+ return 0;
+
+ for (i = 0; i < vdiskcnt; i++)
+ if (hook (virtdisks[i].fullname, hook_data))
+ return 1;
+ return 0;
+}
+
+static grub_err_t
+grub_virtdisk_open (const char *name, grub_disk_t disk)
+{
+ grub_size_t i;
+ grub_uint32_t secsize;
+ char fdir[200];
+ char *buf;
+
+ for (i = 0; i < vdiskcnt; i++)
+ if (grub_strcmp (name, virtdisks[i].fullname) == 0)
+ break;
+ if (i == vdiskcnt)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a virtdisk");
+ disk->data = &virtdisks[i];
+ disk->id = i;
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/sectors", virtdisks[i].backend_dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ if (!buf)
+ return grub_errno;
+ disk->total_sectors = grub_strtoull (buf, 0, 10);
+ if (grub_errno)
+ return grub_errno;
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/sector-size",
+ virtdisks[i].backend_dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ if (!buf)
+ return grub_errno;
+ secsize = grub_strtoull (buf, 0, 10);
+ if (grub_errno)
+ return grub_errno;
+
+ if ((secsize & (secsize - 1)) || !secsize || secsize < 512
+ || secsize > GRUB_XEN_PAGE_SIZE)
+ return grub_error (GRUB_ERR_IO, "unsupported sector size %d", secsize);
+
+ for (disk->log_sector_size = 0;
+ (1U << disk->log_sector_size) < secsize; disk->log_sector_size++);
+
+ disk->total_sectors >>= disk->log_sector_size - 9;
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+grub_virtdisk_close (grub_disk_t disk __attribute__ ((unused)))
+{
+}
+
+static grub_err_t
+grub_virtdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ struct virtdisk *data = disk->data;
+
+ while (size)
+ {
+ grub_size_t cur;
+ struct blkif_request *req;
+ struct blkif_response *resp;
+ int sta = 0;
+ struct evtchn_send send;
+ cur = size;
+ if (cur > (unsigned) (GRUB_XEN_PAGE_SIZE >> disk->log_sector_size))
+ cur = GRUB_XEN_PAGE_SIZE >> disk->log_sector_size;
+ while (RING_FULL (&data->ring))
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ req = RING_GET_REQUEST (&data->ring, data->ring.req_prod_pvt);
+ req->operation = BLKIF_OP_READ;
+ req->nr_segments = 1;
+ req->handle = data->handle;
+ req->id = 0;
+ req->sector_number = sector << (disk->log_sector_size - 9);
+ req->seg[0].gref = data->dma_grant;
+ req->seg[0].first_sect = 0;
+ req->seg[0].last_sect = (cur << (disk->log_sector_size - 9)) - 1;
+ data->ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS (&data->ring);
+ mb ();
+ send.port = data->evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+
+ while (!RING_HAS_UNCONSUMED_RESPONSES (&data->ring))
+ {
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ mb ();
+ }
+ while (1)
+ {
+ int wtd;
+ RING_FINAL_CHECK_FOR_RESPONSES (&data->ring, wtd);
+ if (!wtd)
+ break;
+ resp = RING_GET_RESPONSE (&data->ring, data->ring.rsp_cons);
+ data->ring.rsp_cons++;
+ if (resp->status)
+ sta = resp->status;
+ }
+ if (sta)
+ return grub_error (GRUB_ERR_IO, "read failed");
+ grub_memcpy (buf, data->dma_page, cur << disk->log_sector_size);
+ size -= cur;
+ sector += cur;
+ buf += cur << disk->log_sector_size;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_virtdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, const char *buf)
+{
+ struct virtdisk *data = disk->data;
+
+ while (size)
+ {
+ grub_size_t cur;
+ struct blkif_request *req;
+ struct blkif_response *resp;
+ int sta = 0;
+ struct evtchn_send send;
+ cur = size;
+ if (cur > (unsigned) (GRUB_XEN_PAGE_SIZE >> disk->log_sector_size))
+ cur = GRUB_XEN_PAGE_SIZE >> disk->log_sector_size;
+
+ grub_memcpy (data->dma_page, buf, cur << disk->log_sector_size);
+
+ while (RING_FULL (&data->ring))
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ req = RING_GET_REQUEST (&data->ring, data->ring.req_prod_pvt);
+ req->operation = BLKIF_OP_WRITE;
+ req->nr_segments = 1;
+ req->handle = data->handle;
+ req->id = 0;
+ req->sector_number = sector << (disk->log_sector_size - 9);
+ req->seg[0].gref = data->dma_grant;
+ req->seg[0].first_sect = 0;
+ req->seg[0].last_sect = (cur << (disk->log_sector_size - 9)) - 1;
+ data->ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS (&data->ring);
+ mb ();
+ send.port = data->evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+
+ while (!RING_HAS_UNCONSUMED_RESPONSES (&data->ring))
+ {
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ mb ();
+ }
+ while (1)
+ {
+ int wtd;
+ RING_FINAL_CHECK_FOR_RESPONSES (&data->ring, wtd);
+ if (!wtd)
+ break;
+ resp = RING_GET_RESPONSE (&data->ring, data->ring.rsp_cons);
+ data->ring.rsp_cons++;
+ if (resp->status)
+ sta = resp->status;
+ }
+ if (sta)
+ return grub_error (GRUB_ERR_IO, "write failed");
+ size -= cur;
+ sector += cur;
+ buf += cur << disk->log_sector_size;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_disk_dev grub_virtdisk_dev = {
+ .name = "xen",
+ .id = GRUB_DISK_DEVICE_XEN,
+ .iterate = grub_virtdisk_iterate,
+ .open = grub_virtdisk_open,
+ .close = grub_virtdisk_close,
+ .read = grub_virtdisk_read,
+ .write = grub_virtdisk_write,
+ .next = 0
+};
+
+static int
+count (const char *dir __attribute__ ((unused)), void *data)
+{
+ grub_size_t *ctr = data;
+ (*ctr)++;
+
+ return 0;
+}
+
+static int
+fill (const char *dir, void *data)
+{
+ grub_size_t *ctr = data;
+ domid_t dom;
+ /* "dir" is just a number, at most 19 characters. */
+ char fdir[200];
+ char num[20];
+ grub_err_t err;
+ void *buf;
+ struct evtchn_alloc_unbound alloc_unbound;
+
+ /* Shouldn't happen unles some hotplug happened. */
+ if (vdiskcnt >= *ctr)
+ return 1;
+ virtdisks[vdiskcnt].handle = grub_strtoul (dir, 0, 10);
+ if (grub_errno)
+ {
+ grub_errno = 0;
+ return 0;
+ }
+ virtdisks[vdiskcnt].fullname = 0;
+ virtdisks[vdiskcnt].backend_dir = 0;
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/backend", dir);
+ virtdisks[vdiskcnt].backend_dir = grub_xenstore_get_file (fdir, NULL);
+ if (!virtdisks[vdiskcnt].backend_dir)
+ goto out_fail_1;
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/dev",
+ virtdisks[vdiskcnt].backend_dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ if (!buf)
+ {
+ grub_errno = 0;
+ virtdisks[vdiskcnt].fullname = grub_xasprintf ("xenid/%s", dir);
+ }
+ else
+ {
+ virtdisks[vdiskcnt].fullname = grub_xasprintf ("xen/%s", (char *) buf);
+ grub_free (buf);
+ }
+ if (!virtdisks[vdiskcnt].fullname)
+ goto out_fail_1;
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/backend-id", dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ if (!buf)
+ goto out_fail_1;
+
+ dom = grub_strtoul (buf, 0, 10);
+ grub_free (buf);
+ if (grub_errno)
+ goto out_fail_1;
+
+ virtdisks[vdiskcnt].shared_page =
+ grub_xen_alloc_shared_page (dom, &virtdisks[vdiskcnt].grant);
+ if (!virtdisks[vdiskcnt].shared_page)
+ goto out_fail_1;
+
+ virtdisks[vdiskcnt].dma_page =
+ grub_xen_alloc_shared_page (dom, &virtdisks[vdiskcnt].dma_grant);
+ if (!virtdisks[vdiskcnt].dma_page)
+ goto out_fail_2;
+
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = dom;
+
+ grub_xen_event_channel_op (EVTCHNOP_alloc_unbound, &alloc_unbound);
+ virtdisks[vdiskcnt].evtchn = alloc_unbound.port;
+
+ SHARED_RING_INIT (virtdisks[vdiskcnt].shared_page);
+ FRONT_RING_INIT (&virtdisks[vdiskcnt].ring, virtdisks[vdiskcnt].shared_page,
+ GRUB_XEN_PAGE_SIZE);
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/ring-ref", dir);
+ grub_snprintf (num, sizeof (num), "%u", virtdisks[vdiskcnt].grant);
+ err = grub_xenstore_write_file (fdir, num, grub_strlen (num));
+ if (err)
+ goto out_fail_3;
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/event-channel", dir);
+ grub_snprintf (num, sizeof (num), "%u", virtdisks[vdiskcnt].evtchn);
+ err = grub_xenstore_write_file (fdir, num, grub_strlen (num));
+ if (err)
+ goto out_fail_3;
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/protocol", dir);
+ err = grub_xenstore_write_file (fdir, XEN_IO_PROTO_ABI_NATIVE,
+ grub_strlen (XEN_IO_PROTO_ABI_NATIVE));
+ if (err)
+ goto out_fail_3;
+
+ struct gnttab_dump_table dt;
+ dt.dom = DOMID_SELF;
+ grub_xen_grant_table_op (GNTTABOP_dump_table, (void *) &dt, 1);
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s/state", dir);
+ err = grub_xenstore_write_file (fdir, "3", 1);
+ if (err)
+ goto out_fail_3;
+
+ while (1)
+ {
+ grub_snprintf (fdir, sizeof (fdir), "%s/state",
+ virtdisks[vdiskcnt].backend_dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ if (!buf)
+ goto out_fail_3;
+ if (grub_strcmp (buf, "2") != 0)
+ break;
+ grub_free (buf);
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ }
+ grub_dprintf ("xen", "state=%s\n", (char *) buf);
+ grub_free (buf);
+
+ grub_snprintf (fdir, sizeof (fdir), "device/vbd/%s", dir);
+
+ virtdisks[vdiskcnt].frontend_dir = grub_strdup (fdir);
+
+ vdiskcnt++;
+ return 0;
+
+out_fail_3:
+ grub_xen_free_shared_page (virtdisks[vdiskcnt].dma_page);
+out_fail_2:
+ grub_xen_free_shared_page (virtdisks[vdiskcnt].shared_page);
+out_fail_1:
+ grub_free (virtdisks[vdiskcnt].backend_dir);
+ grub_free (virtdisks[vdiskcnt].fullname);
+
+ grub_errno = 0;
+ return 0;
+}
+
+void
+grub_xendisk_init (void)
+{
+ grub_size_t ctr = 0;
+ if (grub_xenstore_dir ("device/vbd", count, &ctr))
+ grub_errno = 0;
+
+ if (!ctr)
+ return;
+
+ virtdisks = grub_malloc (ctr * sizeof (virtdisks[0]));
+ if (!virtdisks)
+ return;
+ if (grub_xenstore_dir ("device/vbd", fill, &ctr))
+ grub_errno = 0;
+
+ grub_disk_dev_register (&grub_virtdisk_dev);
+}
+
+void
+grub_xendisk_fini (void)
+{
+ char fdir[200];
+ unsigned i;
+
+ for (i = 0; i < vdiskcnt; i++)
+ {
+ char *buf;
+ struct evtchn_close close_op = {.port = virtdisks[i].evtchn };
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/state",
+ virtdisks[i].frontend_dir);
+ grub_xenstore_write_file (fdir, "6", 1);
+
+ while (1)
+ {
+ grub_snprintf (fdir, sizeof (fdir), "%s/state",
+ virtdisks[i].backend_dir);
+ buf = grub_xenstore_get_file (fdir, NULL);
+ grub_dprintf ("xen", "state=%s\n", (char *) buf);
+
+ if (!buf || grub_strcmp (buf, "6") == 0)
+ break;
+ grub_free (buf);
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ }
+ grub_free (buf);
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/ring-ref",
+ virtdisks[i].frontend_dir);
+ grub_xenstore_write_file (fdir, NULL, 0);
+
+ grub_snprintf (fdir, sizeof (fdir), "%s/event-channel",
+ virtdisks[i].frontend_dir);
+ grub_xenstore_write_file (fdir, NULL, 0);
+
+ grub_xen_free_shared_page (virtdisks[i].dma_page);
+ grub_xen_free_shared_page (virtdisks[i].shared_page);
+
+ grub_xen_event_channel_op (EVTCHNOP_close, &close_op);
+ }
+}
return grub_errno;
}
-#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) \
+ && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
static char *cbfsdisk_addr;
static grub_off_t cbfsdisk_size = 0;
GRUB_MOD_INIT (cbfs)
{
-#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
init_cbfsdisk ();
#endif
grub_fs_register (&grub_cbfs_fs);
GRUB_MOD_FINI (cbfs)
{
grub_fs_unregister (&grub_cbfs_fs);
-#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
+#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
fini_cbfsdisk ();
#endif
}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/file.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_offset_file
+{
+ grub_file_t parent;
+ grub_off_t off;
+};
+
+static grub_ssize_t
+grub_offset_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_offset_file *data = file->data;
+ if (grub_file_seek (data->parent, data->off + file->offset) == (grub_off_t) -1)
+ return -1;
+ return grub_file_read (data->parent, buf, len);
+}
+
+static grub_err_t
+grub_offset_close (grub_file_t file)
+{
+ struct grub_offset_file *data = file->data;
+
+ if (data->parent)
+ grub_file_close (data->parent);
+
+ /* No need to close the same device twice. */
+ file->device = 0;
+
+ return 0;
+}
+
+static struct grub_fs grub_offset_fs = {
+ .name = "offset",
+ .dir = 0,
+ .open = 0,
+ .read = grub_offset_read,
+ .close = grub_offset_close,
+ .label = 0,
+ .next = 0
+};
+
+void
+grub_file_offset_close (grub_file_t file)
+{
+ struct grub_offset_file *off_data = file->data;
+ off_data->parent = NULL;
+ grub_file_close (file);
+}
+
+grub_file_t
+grub_file_offset_open (grub_file_t parent, grub_off_t start, grub_off_t size)
+{
+ struct grub_offset_file *off_data;
+ grub_file_t off_file, last_off_file;
+ grub_file_filter_id_t filter;
+
+ off_file = grub_zalloc (sizeof (*off_file));
+ off_data = grub_zalloc (sizeof (*off_data));
+ if (!off_file || !off_data)
+ {
+ grub_free (off_file);
+ grub_free (off_data);
+ return 0;
+ }
+
+ off_data->off = start;
+ off_data->parent = parent;
+
+ off_file->device = parent->device;
+ off_file->data = off_data;
+ off_file->fs = &grub_offset_fs;
+ off_file->size = size;
+
+ last_off_file = NULL;
+ for (filter = GRUB_FILE_FILTER_COMPRESSION_FIRST;
+ off_file && filter <= GRUB_FILE_FILTER_COMPRESSION_LAST; filter++)
+ if (grub_file_filters_enabled[filter])
+ {
+ last_off_file = off_file;
+ off_file = grub_file_filters_enabled[filter] (off_file, parent->name);
+ }
+
+ if (!off_file)
+ {
+ off_data->parent = NULL;
+ grub_file_close (last_off_file);
+ return 0;
+ }
+ return off_file;
+}
#include <grub/env.h>
#include <grub/partition.h>
#include <grub/i18n.h>
+#include <grub/loader.h>
#include <grub/util/misc.h>
#include "progname.h"
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_console_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_console_fini ();
}
\f
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_vga_text_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_vga_text_fini ();
grub_stop_floppy ();
}
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_efi_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_efi_fini ();
}
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_console_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_console_fini ();
grub_stop_floppy ();
}
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_vga_text_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_vga_text_fini ();
grub_stop_floppy ();
}
#include <grub/misc.h>
#include <grub/i386/tsc.h>
#include <grub/i386/cpuid.h>
+#ifdef GRUB_MACHINE_XEN
+#include <grub/xen.h>
+#else
#include <grub/i386/pit.h>
+#endif
#include <grub/cpu/io.h>
/* This defines the value TSC had at the epoch (that is, when we calibrated it). */
return (d & (1 << 4)) != 0;
}
+#ifndef GRUB_MACHINE_XEN
+
static void
grub_pit_wait (grub_uint16_t tics)
{
& ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
GRUB_PIT_SPEAKER_PORT);
}
+#endif
static grub_uint64_t
grub_tsc_get_time_ms (void)
return ((al * grub_tsc_rate) >> 32) + ah * grub_tsc_rate;
}
+#ifndef GRUB_MACHINE_XEN
/* Calibrate the TSC based on the RTC. */
static void
calibrate_tsc (void)
grub_tsc_rate = grub_divmod64 ((55ULL << 32), end_tsc - tsc_boot_time, 0);
}
+#endif
void
grub_tsc_init (void)
{
+#ifdef GRUB_MACHINE_XEN
+ grub_uint64_t t;
+ tsc_boot_time = grub_get_tsc ();
+ t = grub_xen_shared_info->vcpu_info[0].time.tsc_to_system_mul;
+ if (grub_xen_shared_info->vcpu_info[0].time.tsc_shift > 0)
+ t <<= grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
+ else
+ t >>= -grub_xen_shared_info->vcpu_info[0].time.tsc_shift;
+ grub_tsc_rate = grub_divmod64 (t, 1000000, 0);
+ grub_install_get_time_ms (grub_tsc_get_time_ms);
+#else
if (grub_cpu_is_tsc_supported ())
{
calibrate_tsc ();
grub_fatal ("no TSC found");
#endif
}
+#endif
}
--- /dev/null
+/* hypercall.S - wrappers for Xen hypercalls */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/symbol.h>
+#include <grub/xen.h>
+
+FUNCTION(grub_xen_hypercall)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ /* call number already in %eax. */
+ /* %edx -> %ebx*/
+ /* %ecx -> %ecx*/
+ movl %edx, %ebx
+ movl 8(%ebp), %edx
+ movl 12(%ebp), %esi
+ movl 16(%ebp), %edi
+ movl 20(%ebp), %ebp
+ int $0x82
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ retl $16
--- /dev/null
+/* startup.S - bootstrap GRUB itself */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/symbol.h>
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+ .code32
+
+start:
+_start:
+ leal LOCAL(stack_end), %esp
+ movl %esi, EXT_C(grub_xen_start_page_addr)
+
+ call EXT_C(grub_main)
+ /* Doesn't return. */
+
+ .bss
+ .space (1 << 22)
+LOCAL(stack_end):
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_efi_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ grub_efi_fini ();
}
void
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
{
- grub_ofdisk_fini ();
- grub_console_fini ();
+ if (flags & GRUB_LOADER_FLAG_NORETURN)
+ {
+ grub_ofdisk_fini ();
+ grub_console_fini ();
+ }
}
grub_uint64_t
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
{
}
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
{
}
}
void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
{
}
--- /dev/null
+/* hypercall.S - wrappers for Xen hypercalls */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/symbol.h>
+#include <grub/xen.h>
+
+FUNCTION(grub_xen_sched_op)
+ movq $__HYPERVISOR_sched_op, %rax
+ syscall
+ ret
+
+FUNCTION(grub_xen_event_channel_op)
+ movq $__HYPERVISOR_event_channel_op, %rax
+ syscall
+ ret
+
+FUNCTION(grub_xen_update_va_mapping)
+ movq $__HYPERVISOR_update_va_mapping, %rax
+ syscall
+ ret
+
+FUNCTION(grub_xen_mmuext_op)
+ movq %rcx, %r10
+ movq $__HYPERVISOR_mmuext_op, %rax
+ syscall
+ ret
+
+FUNCTION(grub_xen_grant_table_op)
+ movq $__HYPERVISOR_grant_table_op, %rax
+ syscall
+ ret
+
+FUNCTION(grub_xen_mmu_update)
+ movq %rcx, %r10
+ movq $__HYPERVISOR_mmu_update, %rax
+ syscall
+ ret
--- /dev/null
+/* startup.S - bootstrap GRUB itself */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/symbol.h>
+
+ .file "startup.S"
+ .text
+ .globl start, _start
+ .code64
+
+start:
+_start:
+ leaq LOCAL(stack_end), %rsp
+ movq %rsi, EXT_C(grub_xen_start_page_addr)(%rip)
+
+ call EXT_C(grub_main)
+ /* Doesn't return. */
+
+ .bss
+ .space (1 << 22)
+LOCAL(stack_end):
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/xen.h>
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/mm.h>
+#include <grub/kernel.h>
+#include <grub/offsets.h>
+#include <grub/memory.h>
+#include <grub/i386/tsc.h>
+#include <grub/term.h>
+#include <grub/loader.h>
+
+grub_addr_t grub_modbase;
+struct start_info *grub_xen_start_page_addr;
+volatile struct xencons_interface *grub_xen_xcons;
+volatile struct shared_info *grub_xen_shared_info;
+volatile struct xenstore_domain_interface *grub_xen_xenstore;
+volatile grant_entry_v2_t *grub_xen_grant_table;
+static const grub_size_t total_grants =
+ GRUB_XEN_PAGE_SIZE / sizeof (grub_xen_grant_table[0]);
+grub_size_t grub_xen_n_allocated_shared_pages;
+
+static grub_xen_mfn_t
+grub_xen_ptr2mfn (void *ptr)
+{
+ grub_xen_mfn_t *mfn_list =
+ (grub_xen_mfn_t *) grub_xen_start_page_addr->mfn_list;
+ return mfn_list[(grub_addr_t) ptr >> GRUB_XEN_LOG_PAGE_SIZE];
+}
+
+void *
+grub_xen_alloc_shared_page (domid_t dom, grub_xen_grant_t * grnum)
+{
+ void *ret;
+ grub_xen_mfn_t mfn;
+ volatile grant_entry_v2_t *entry;
+
+ /* Avoid 0. */
+ for (entry = grub_xen_grant_table;
+ entry < grub_xen_grant_table + total_grants; entry++)
+ if (!entry->hdr.flags)
+ break;
+
+ if (entry == grub_xen_grant_table + total_grants)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of grant entries");
+ return NULL;
+ }
+ ret = grub_memalign (GRUB_XEN_PAGE_SIZE, GRUB_XEN_PAGE_SIZE);
+ if (!ret)
+ return NULL;
+ mfn = grub_xen_ptr2mfn (ret);
+ entry->full_page.pad0 = 0;
+ entry->full_page.frame = mfn;
+ entry->full_page.hdr.domid = dom;
+ mb ();
+ entry->full_page.hdr.flags = GTF_permit_access;
+ mb ();
+ *grnum = entry - grub_xen_grant_table;
+ grub_xen_n_allocated_shared_pages++;
+ return ret;
+}
+
+void
+grub_xen_free_shared_page (void *ptr)
+{
+ grub_xen_mfn_t mfn;
+ volatile grant_entry_v2_t *entry;
+
+ mfn = grub_xen_ptr2mfn (ptr);
+ for (entry = grub_xen_grant_table + 1;
+ entry < grub_xen_grant_table + total_grants; entry++)
+ if (entry->hdr.flags && entry->full_page.frame == mfn)
+ {
+ mb ();
+ entry->hdr.flags = 0;
+ mb ();
+ entry->full_page.frame = 0;
+ mb ();
+ }
+ grub_xen_n_allocated_shared_pages--;
+}
+
+void
+grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
+ char **path __attribute__ ((unused)))
+{
+}
+
+static grub_uint8_t window[GRUB_XEN_PAGE_SIZE]
+ __attribute__ ((aligned (GRUB_XEN_PAGE_SIZE)));
+
+#ifdef __x86_64__
+#define NUMBER_OF_LEVELS 4
+#else
+#define NUMBER_OF_LEVELS 3
+#endif
+
+#define LOG_POINTERS_PER_PAGE 9
+#define POINTERS_PER_PAGE (1 << LOG_POINTERS_PER_PAGE)
+
+void
+grub_xen_store_send (const void *buf_, grub_size_t len)
+{
+ const grub_uint8_t *buf = buf_;
+ struct evtchn_send send;
+ int event_sent = 0;
+ while (len)
+ {
+ grub_size_t avail, inbuf;
+ grub_size_t prod, cons;
+ mb ();
+ prod = grub_xen_xenstore->req_prod;
+ cons = grub_xen_xenstore->req_cons;
+ if (prod >= cons + sizeof (grub_xen_xenstore->req))
+ {
+ if (!event_sent)
+ {
+ send.port = grub_xen_start_page_addr->store_evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+ event_sent = 1;
+ }
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ continue;
+ }
+ event_sent = 0;
+ avail = cons + sizeof (grub_xen_xenstore->req) - prod;
+ inbuf = (~prod & (sizeof (grub_xen_xenstore->req) - 1)) + 1;
+ if (avail > inbuf)
+ avail = inbuf;
+ if (avail > len)
+ avail = len;
+ grub_memcpy ((void *) &grub_xen_xenstore->req[prod & (sizeof (grub_xen_xenstore->req) - 1)],
+ buf, avail);
+ buf += avail;
+ len -= avail;
+ mb ();
+ grub_xen_xenstore->req_prod += avail;
+ mb ();
+ if (!event_sent)
+ {
+ send.port = grub_xen_start_page_addr->store_evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+ event_sent = 1;
+ }
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ }
+}
+
+void
+grub_xen_store_recv (void *buf_, grub_size_t len)
+{
+ grub_uint8_t *buf = buf_;
+ struct evtchn_send send;
+ int event_sent = 0;
+ while (len)
+ {
+ grub_size_t avail, inbuf;
+ grub_size_t prod, cons;
+ mb ();
+ prod = grub_xen_xenstore->rsp_prod;
+ cons = grub_xen_xenstore->rsp_cons;
+ if (prod <= cons)
+ {
+ if (!event_sent)
+ {
+ send.port = grub_xen_start_page_addr->store_evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+ event_sent = 1;
+ }
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ continue;
+ }
+ event_sent = 0;
+ avail = prod - cons;
+ inbuf = (~cons & (sizeof (grub_xen_xenstore->req) - 1)) + 1;
+ if (avail > inbuf)
+ avail = inbuf;
+ if (avail > len)
+ avail = len;
+ grub_memcpy (buf,
+ (void *) &grub_xen_xenstore->rsp[cons & (sizeof (grub_xen_xenstore->rsp) - 1)],
+ avail);
+ buf += avail;
+ len -= avail;
+ mb ();
+ grub_xen_xenstore->rsp_cons += avail;
+ mb ();
+ if (!event_sent)
+ {
+ send.port = grub_xen_start_page_addr->store_evtchn;
+ grub_xen_event_channel_op(EVTCHNOP_send, &send);
+ event_sent = 1;
+ }
+ grub_xen_sched_op(SCHEDOP_yield, 0);
+ }
+}
+
+void *
+grub_xenstore_get_file (const char *dir, grub_size_t *len)
+{
+ struct xsd_sockmsg msg;
+ char *buf;
+ grub_size_t dirlen = grub_strlen (dir) + 1;
+
+ if (len)
+ *len = 0;
+
+ grub_memset (&msg, 0, sizeof (msg));
+ msg.type = XS_READ;
+ msg.len = dirlen;
+ grub_xen_store_send (&msg, sizeof (msg));
+ grub_xen_store_send (dir, dirlen);
+ grub_xen_store_recv (&msg, sizeof (msg));
+ buf = grub_malloc (msg.len + 1);
+ if (!buf)
+ return NULL;
+ grub_dprintf ("xen", "msg type = %d, len = %d\n", msg.type, msg.len);
+ grub_xen_store_recv (buf, msg.len);
+ buf[msg.len] = '\0';
+ if (msg.type == XS_ERROR)
+ {
+ grub_error (GRUB_ERR_IO, "couldn't read xenstorage `%s': %s", dir, buf);
+ grub_free (buf);
+ return NULL;
+ }
+ if (len)
+ *len = msg.len;
+ return buf;
+}
+
+grub_err_t
+grub_xenstore_write_file (const char *dir, const void *buf, grub_size_t len)
+{
+ struct xsd_sockmsg msg;
+ grub_size_t dirlen = grub_strlen (dir) + 1;
+ char *resp;
+
+ grub_memset (&msg, 0, sizeof (msg));
+ msg.type = XS_WRITE;
+ msg.len = dirlen + len + 1;
+ grub_xen_store_send (&msg, sizeof (msg));
+ grub_xen_store_send (dir, dirlen);
+ grub_xen_store_send (buf, len);
+ grub_xen_store_send ("", 1);
+ grub_xen_store_recv (&msg, sizeof (msg));
+ resp = grub_malloc (msg.len + 1);
+ if (!resp)
+ return grub_errno;
+ grub_dprintf ("xen", "msg type = %d, len = %d\n", msg.type, msg.len);
+ grub_xen_store_recv (resp, msg.len);
+ resp[msg.len] = '\0';
+ if (msg.type == XS_ERROR)
+ {
+ grub_dprintf ("xen", "error = %s\n", resp);
+ grub_error (GRUB_ERR_IO, "couldn't read xenstorage `%s': %s",
+ dir, resp);
+ grub_free (resp);
+ return grub_errno;
+ }
+ grub_free (resp);
+ return GRUB_ERR_NONE;
+}
+
+/* FIXME: error handling. */
+grub_err_t
+grub_xenstore_dir (const char *dir,
+ int (*hook) (const char *dir, void *hook_data),
+ void *hook_data)
+{
+ struct xsd_sockmsg msg;
+ char *buf;
+ char *ptr;
+ grub_size_t dirlen = grub_strlen (dir) + 1;
+
+ grub_memset (&msg, 0, sizeof (msg));
+ msg.type = XS_DIRECTORY;
+ msg.len = dirlen;
+ grub_xen_store_send (&msg, sizeof (msg));
+ grub_xen_store_send (dir, dirlen);
+ grub_xen_store_recv (&msg, sizeof (msg));
+ buf = grub_malloc (msg.len + 1);
+ if (!buf)
+ return grub_errno;
+ grub_dprintf ("xen", "msg type = %d, len = %d\n", msg.type, msg.len);
+ grub_xen_store_recv (buf, msg.len);
+ buf[msg.len] = '\0';
+ if (msg.type == XS_ERROR)
+ {
+ grub_err_t err;
+ err = grub_error (GRUB_ERR_IO, "couldn't read xenstorage `%s': %s",
+ dir, buf);
+ grub_free (buf);
+ return err;
+ }
+ for (ptr = buf; ptr < buf + msg.len; ptr += grub_strlen (ptr) + 1)
+ if (hook (ptr, hook_data))
+ break;
+ grub_free (buf);
+ return grub_errno;
+}
+
+unsigned long gntframe = 0;
+
+#define MAX_N_UNUSABLE_PAGES 4
+
+static int
+grub_xen_is_page_usable (grub_xen_mfn_t mfn)
+{
+ if (mfn == grub_xen_start_page_addr->console.domU.mfn)
+ return 0;
+ if (mfn == grub_xen_start_page_addr->shared_info)
+ return 0;
+ if (mfn == grub_xen_start_page_addr->store_mfn)
+ return 0;
+ if (mfn == gntframe)
+ return 0;
+ return 1;
+}
+
+static grub_uint64_t
+page2offset (grub_uint64_t page)
+{
+ return page << 12;
+}
+
+static void
+map_all_pages (void)
+{
+ grub_uint64_t total_pages = grub_xen_start_page_addr->nr_pages;
+ grub_uint64_t i, j;
+ grub_xen_mfn_t *mfn_list =
+ (grub_xen_mfn_t *) grub_xen_start_page_addr->mfn_list;
+ grub_uint64_t *pg = (grub_uint64_t *) window;
+ grub_uint64_t oldpgstart, oldpgend;
+ struct gnttab_setup_table gnttab_setup;
+ struct gnttab_set_version gnttab_setver;
+ grub_size_t n_unusable_pages = 0;
+ struct mmu_update m2p_updates[2 * MAX_N_UNUSABLE_PAGES];
+
+ grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
+
+ gnttab_setver.version = 2;
+ grub_xen_grant_table_op (GNTTABOP_set_version, &gnttab_setver, 1);
+
+ grub_memset (&gnttab_setup, 0, sizeof (gnttab_setup));
+ gnttab_setup.dom = DOMID_SELF;
+ gnttab_setup.nr_frames = 1;
+ gnttab_setup.frame_list.p = &gntframe;
+
+ grub_xen_grant_table_op (GNTTABOP_setup_table, &gnttab_setup, 1);
+
+ for (j = 0; j < total_pages - n_unusable_pages; j++)
+ while (!grub_xen_is_page_usable (mfn_list[j]))
+ {
+ grub_xen_mfn_t t;
+ if (n_unusable_pages >= MAX_N_UNUSABLE_PAGES)
+ {
+ struct sched_shutdown arg;
+ arg.reason = SHUTDOWN_crash;
+ grub_xen_sched_op (SCHEDOP_shutdown, &arg);
+ while (1);
+ }
+ t = mfn_list[j];
+ mfn_list[j] = mfn_list[total_pages - n_unusable_pages - 1];
+ mfn_list[total_pages - n_unusable_pages - 1] = t;
+
+ m2p_updates[2 * n_unusable_pages].ptr
+ = page2offset (mfn_list[j]) | MMU_MACHPHYS_UPDATE;
+ m2p_updates[2 * n_unusable_pages].val = j;
+ m2p_updates[2 * n_unusable_pages + 1].ptr
+ = page2offset (mfn_list[total_pages - n_unusable_pages - 1])
+ | MMU_MACHPHYS_UPDATE;
+ m2p_updates[2 * n_unusable_pages + 1].val = total_pages
+ - n_unusable_pages - 1;
+
+ n_unusable_pages++;
+ }
+
+ grub_xen_mmu_update (m2p_updates, 2 * n_unusable_pages, NULL, DOMID_SELF);
+
+ total_pages += 4;
+
+ grub_uint64_t lx[NUMBER_OF_LEVELS], nlx;
+ grub_uint64_t paging_start = total_pages - 4 - n_unusable_pages, curpage;
+
+ for (nlx = total_pages, i = 0; i < (unsigned) NUMBER_OF_LEVELS; i++)
+ {
+ nlx = (nlx + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
+ /* PAE wants all 4 root directories present. */
+#ifdef __i386__
+ if (i == 1)
+ nlx = 4;
+#endif
+ lx[i] = nlx;
+ paging_start -= nlx;
+ }
+
+ oldpgstart = grub_xen_start_page_addr->pt_base >> 12;
+ oldpgend = oldpgstart + grub_xen_start_page_addr->nr_pt_frames;
+
+ curpage = paging_start;
+
+ int l;
+
+ for (l = NUMBER_OF_LEVELS - 1; l >= 1; l--)
+ {
+ for (i = 0; i < lx[l]; i++)
+ {
+ grub_xen_update_va_mapping (&window,
+ page2offset (mfn_list[curpage + i]) | 7,
+ UVMF_INVLPG);
+ grub_memset (&window, 0, sizeof (window));
+
+ for (j = i * POINTERS_PER_PAGE;
+ j < (i + 1) * POINTERS_PER_PAGE && j < lx[l - 1]; j++)
+ pg[j - i * POINTERS_PER_PAGE] =
+ page2offset (mfn_list[curpage + lx[l] + j])
+#ifdef __x86_64__
+ | 4
+#endif
+ | 3;
+ }
+ curpage += lx[l];
+ }
+
+ for (i = 0; i < lx[0]; i++)
+ {
+ grub_xen_update_va_mapping (&window,
+ page2offset (mfn_list[curpage + i]) | 7,
+ UVMF_INVLPG);
+ grub_memset (&window, 0, sizeof (window));
+
+ for (j = i * POINTERS_PER_PAGE;
+ j < (i + 1) * POINTERS_PER_PAGE && j < total_pages; j++)
+ if (j < paging_start && !(j >= oldpgstart && j < oldpgend))
+ pg[j - i * POINTERS_PER_PAGE] = page2offset (mfn_list[j]) | 0x7;
+ else if (j < grub_xen_start_page_addr->nr_pages)
+ pg[j - i * POINTERS_PER_PAGE] = page2offset (mfn_list[j]) | 5;
+ else if (j == grub_xen_start_page_addr->nr_pages)
+ {
+ pg[j - i * POINTERS_PER_PAGE] =
+ page2offset (grub_xen_start_page_addr->console.domU.mfn) | 7;
+ grub_xen_xcons = (void *) (grub_addr_t) page2offset (j);
+ }
+ else if (j == grub_xen_start_page_addr->nr_pages + 1)
+ {
+ pg[j - i * POINTERS_PER_PAGE] =
+ grub_xen_start_page_addr->shared_info | 7;
+ grub_xen_shared_info = (void *) (grub_addr_t) page2offset (j);
+ }
+ else if (j == grub_xen_start_page_addr->nr_pages + 2)
+ {
+ pg[j - i * POINTERS_PER_PAGE] =
+ page2offset (grub_xen_start_page_addr->store_mfn) | 7;
+ grub_xen_xenstore = (void *) (grub_addr_t) page2offset (j);
+ }
+ else if (j == grub_xen_start_page_addr->nr_pages + 3)
+ {
+ pg[j - i * POINTERS_PER_PAGE] = page2offset (gntframe) | 7;
+ grub_xen_grant_table = (void *) (grub_addr_t) page2offset (j);
+ }
+ }
+
+ grub_xen_update_va_mapping (&window, 0, UVMF_INVLPG);
+
+ mmuext_op_t op[3];
+
+ op[0].cmd = MMUEXT_PIN_L1_TABLE + (NUMBER_OF_LEVELS - 1);
+ op[0].arg1.mfn = mfn_list[paging_start];
+ op[1].cmd = MMUEXT_NEW_BASEPTR;
+ op[1].arg1.mfn = mfn_list[paging_start];
+ op[2].cmd = MMUEXT_UNPIN_TABLE;
+ op[2].arg1.mfn = mfn_list[oldpgstart];
+
+ grub_xen_mmuext_op (op, 3, NULL, DOMID_SELF);
+
+ for (i = oldpgstart; i < oldpgend; i++)
+ grub_xen_update_va_mapping ((void *) (grub_addr_t) page2offset (i),
+ page2offset (mfn_list[i]) | 7, UVMF_INVLPG);
+ void *new_start_page, *new_mfn_list;
+ new_start_page = (void *) (grub_addr_t) page2offset (paging_start - 1);
+ grub_memcpy (new_start_page, grub_xen_start_page_addr, 4096);
+ grub_xen_start_page_addr = new_start_page;
+ new_mfn_list = (void *) (grub_addr_t)
+ page2offset (paging_start - 1
+ - ((grub_xen_start_page_addr->nr_pages
+ * sizeof (grub_uint64_t) + 4095) / 4096));
+ grub_memcpy (new_mfn_list, mfn_list, grub_xen_start_page_addr->nr_pages
+ * sizeof (grub_uint64_t));
+ grub_xen_start_page_addr->pt_base = page2offset (paging_start);
+ grub_xen_start_page_addr->mfn_list = (grub_addr_t) new_mfn_list;
+
+ grub_addr_t heap_start = grub_modules_get_end ();
+ grub_addr_t heap_end = (grub_addr_t) new_mfn_list;
+
+ grub_mm_init_region ((void *) heap_start, heap_end - heap_start);
+}
+
+extern char _end[];
+
+void
+grub_machine_init (void)
+{
+#ifdef __i386__
+ grub_xen_vm_assist (VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+#endif
+
+ grub_modbase = ALIGN_UP ((grub_addr_t) _end
+ + GRUB_KERNEL_MACHINE_MOD_GAP,
+ GRUB_KERNEL_MACHINE_MOD_ALIGN);
+
+ map_all_pages ();
+
+ grub_console_init ();
+
+ grub_tsc_init ();
+
+ grub_xendisk_init ();
+
+ grub_boot_init ();
+}
+
+void
+grub_exit (void)
+{
+ struct sched_shutdown arg;
+
+ arg.reason = SHUTDOWN_poweroff;
+ grub_xen_sched_op (SCHEDOP_shutdown, &arg);
+ while (1);
+}
+
+void
+grub_machine_fini (int flags __attribute__ ((unused)))
+{
+ grub_xendisk_fini ();
+ grub_boot_fini ();
+}
+
+grub_err_t
+grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
+ grub_uint64_t total_pages = grub_xen_start_page_addr->nr_pages;
+ grub_uint64_t usable_pages = grub_xen_start_page_addr->pt_base >> 12;
+ if (hook (0, page2offset (usable_pages), GRUB_MEMORY_AVAILABLE, hook_data))
+ return GRUB_ERR_NONE;
+
+ hook (page2offset (usable_pages), page2offset (total_pages - usable_pages),
+ GRUB_MEMORY_RESERVED, hook_data);
+
+ return GRUB_ERR_NONE;
+}
#include <grub/i386/relocator_private.h>
#include <grub/i386/pc/int.h>
-extern grub_uint8_t grub_relocator_forward_start;
-extern grub_uint8_t grub_relocator_forward_end;
-extern grub_uint8_t grub_relocator_backward_start;
-extern grub_uint8_t grub_relocator_backward_end;
-
-extern void *grub_relocator_backward_dest;
-extern void *grub_relocator_backward_src;
-extern grub_size_t grub_relocator_backward_chunk_size;
-
-extern void *grub_relocator_forward_dest;
-extern void *grub_relocator_forward_src;
-extern grub_size_t grub_relocator_forward_chunk_size;
-
extern grub_uint8_t grub_relocator16_start;
extern grub_uint8_t grub_relocator16_end;
extern grub_uint16_t grub_relocator16_cs;
#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
-grub_size_t grub_relocator_align = 1;
-grub_size_t grub_relocator_forward_size;
-grub_size_t grub_relocator_backward_size;
-#ifdef __x86_64__
-grub_size_t grub_relocator_jumper_size = 12;
-#else
-grub_size_t grub_relocator_jumper_size = 7;
-#endif
-
-void
-grub_cpu_relocator_init (void)
-{
- grub_relocator_forward_size = RELOCATOR_SIZEOF(_forward);
- grub_relocator_backward_size = RELOCATOR_SIZEOF(_backward);
-}
-
-void
-grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
-{
- grub_uint8_t *ptr;
- ptr = rels;
-#ifdef __x86_64__
- /* movq imm64, %rax (for relocator) */
- *(grub_uint8_t *) ptr = 0x48;
- ptr++;
- *(grub_uint8_t *) ptr = 0xb8;
- ptr++;
- *(grub_uint64_t *) ptr = addr;
- ptr += sizeof (grub_uint64_t);
-#else
- /* movl imm32, %eax (for relocator) */
- *(grub_uint8_t *) ptr = 0xb8;
- ptr++;
- *(grub_uint32_t *) ptr = addr;
- ptr += sizeof (grub_uint32_t);
-#endif
- /* jmp $eax/$rax */
- *(grub_uint8_t *) ptr = 0xff;
- ptr++;
- *(grub_uint8_t *) ptr = 0xe0;
- ptr++;
-}
-
-void
-grub_cpu_relocator_backward (void *ptr, void *src, void *dest,
- grub_size_t size)
-{
- grub_relocator_backward_dest = dest;
- grub_relocator_backward_src = src;
- grub_relocator_backward_chunk_size = size;
-
- grub_memmove (ptr,
- &grub_relocator_backward_start,
- RELOCATOR_SIZEOF (_backward));
-}
-
-void
-grub_cpu_relocator_forward (void *ptr, void *src, void *dest,
- grub_size_t size)
-{
- grub_relocator_forward_dest = dest;
- grub_relocator_forward_src = src;
- grub_relocator_forward_chunk_size = size;
-
- grub_memmove (ptr,
- &grub_relocator_forward_start,
- RELOCATOR_SIZEOF (_forward));
-}
-
grub_err_t
grub_relocator32_boot (struct grub_relocator *rel,
struct grub_relocator32_state state,
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009-2013 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/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/term.h>
+
+#include <grub/relocator.h>
+#include <grub/relocator_private.h>
+
+extern grub_uint8_t grub_relocator_forward_start;
+extern grub_uint8_t grub_relocator_forward_end;
+extern grub_uint8_t grub_relocator_backward_start;
+extern grub_uint8_t grub_relocator_backward_end;
+
+extern void *grub_relocator_backward_dest;
+extern void *grub_relocator_backward_src;
+extern grub_size_t grub_relocator_backward_chunk_size;
+
+extern void *grub_relocator_forward_dest;
+extern void *grub_relocator_forward_src;
+extern grub_size_t grub_relocator_forward_chunk_size;
+
+#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
+
+grub_size_t grub_relocator_align = 1;
+grub_size_t grub_relocator_forward_size;
+grub_size_t grub_relocator_backward_size;
+#ifdef __x86_64__
+grub_size_t grub_relocator_jumper_size = 12;
+#else
+grub_size_t grub_relocator_jumper_size = 7;
+#endif
+
+void
+grub_cpu_relocator_init (void)
+{
+ grub_relocator_forward_size = RELOCATOR_SIZEOF (_forward);
+ grub_relocator_backward_size = RELOCATOR_SIZEOF (_backward);
+}
+
+void
+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
+{
+ grub_uint8_t *ptr;
+ ptr = rels;
+#ifdef __x86_64__
+ /* movq imm64, %rax (for relocator) */
+ *(grub_uint8_t *) ptr = 0x48;
+ ptr++;
+ *(grub_uint8_t *) ptr = 0xb8;
+ ptr++;
+ *(grub_uint64_t *) ptr = addr;
+ ptr += sizeof (grub_uint64_t);
+#else
+ /* movl imm32, %eax (for relocator) */
+ *(grub_uint8_t *) ptr = 0xb8;
+ ptr++;
+ *(grub_uint32_t *) ptr = addr;
+ ptr += sizeof (grub_uint32_t);
+#endif
+ /* jmp $eax/$rax */
+ *(grub_uint8_t *) ptr = 0xff;
+ ptr++;
+ *(grub_uint8_t *) ptr = 0xe0;
+ ptr++;
+}
+
+void
+grub_cpu_relocator_backward (void *ptr, void *src, void *dest,
+ grub_size_t size)
+{
+ grub_relocator_backward_dest = dest;
+ grub_relocator_backward_src = src;
+ grub_relocator_backward_chunk_size = size;
+
+ grub_memmove (ptr,
+ &grub_relocator_backward_start, RELOCATOR_SIZEOF (_backward));
+}
+
+void
+grub_cpu_relocator_forward (void *ptr, void *src, void *dest,
+ grub_size_t size)
+{
+ grub_relocator_forward_dest = dest;
+ grub_relocator_forward_src = src;
+ grub_relocator_forward_chunk_size = size;
+
+ grub_memmove (ptr,
+ &grub_relocator_forward_start, RELOCATOR_SIZEOF (_forward));
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/symbol.h>
+#include <grub/xen.h>
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator_xen_remap_start)
+LOCAL(base):
+ /* mov imm32, %ebx */
+ .byte 0xbb
+VARIABLE(grub_relocator_xen_remapper_virt)
+ .long 0
+
+ /* mov imm32, %ecx */
+ .byte 0xb9
+VARIABLE(grub_relocator_xen_remapper_map)
+ .long 0
+
+ /* mov imm32, %edx */
+ .byte 0xba
+VARIABLE(grub_relocator_xen_remapper_map_high)
+ .long 0
+
+ movl $2, %esi
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82
+
+ addl $(LOCAL(cont) - LOCAL(base)), %ebx
+
+ jmp *%ebx
+
+LOCAL(cont):
+
+ /* mov imm32, %ecx */
+ .byte 0xb9
+VARIABLE(grub_relocator_xen_paging_size)
+ .long 0
+
+ /* mov imm32, %ebx */
+ .byte 0xbb
+VARIABLE(grub_relocator_xen_paging_start)
+ .long 0
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_mfn_list)
+ .long 0
+
+ movl %eax, %edi
+1:
+ movl %ecx, %ebp
+ movl 0(%edi), %ecx
+ movl %ecx, %edx
+ shll $12, %ecx
+ shrl $20, %edx
+ orl $5, %ecx
+ movl $2, %esi
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82
+
+ movl %ebp, %ecx
+ addl $4, %edi
+ addl $4096, %ebx
+
+ loop 1b
+
+ /* mov imm32, %ebx */
+ .byte 0xbb
+VARIABLE(grub_relocator_xen_mmu_op_addr)
+ .long 0
+ movl $3, %ecx
+ movl $0, %edx
+ movl $0x7FF0, %esi
+ movl $__HYPERVISOR_mmuext_op, %eax
+ int $0x82
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remap_continue)
+ .long 0
+
+ jmp *%eax
+
+VARIABLE(grub_relocator_xen_mmu_op)
+ .space 256
+
+VARIABLE(grub_relocator_xen_remap_end)
+
+
+VARIABLE(grub_relocator_xen_start)
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remapper_virt2)
+ .long 0
+
+ movl %eax, %edi
+
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+
+ movl $2, %esi
+ movl $__HYPERVISOR_update_va_mapping, %eax
+ int $0x82
+
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_stack)
+ .long 0
+
+ movl %eax, %esp
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_start_info)
+ .long 0
+
+ movl %eax, %esi
+
+ cld
+
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_entry_point)
+ .long 0
+
+ jmp *%eax
+
+VARIABLE(grub_relocator_xen_end)
{"pause", "echo %s; if ! sleep -i 60; then return; fi\n", NULL, 0, 1,
{TYPE_REST_VERBATIM}, 0,
"[MESSAGE ...]", "Print MESSAGE, then wait until a key is pressed."},
+ {"print", "echo %s\n", NULL, 0, 1,
+ {TYPE_REST_VERBATIM}, 0,
+ "[MESSAGE ...]", "Print MESSAGE."},
/* FIXME: quit unsupported. */
/* FIXME: rarp unsupported. */
{"read", "read_dword %s\n", NULL, 0, 1, {TYPE_INT}, 0, "ADDR",
#ifdef GRUB_MACHINE_EFI
grub_efi_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx,
avoid_efi_boot_services);
-#elif defined (__powerpc__)
+#elif defined (__powerpc__) || defined (GRUB_MACHINE_XEN)
(void) avoid_efi_boot_services;
grub_machine_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx);
#else
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/symbol.h>
+#include <grub/xen.h>
+
+ .p2align 4 /* force 16-byte alignment */
+
+VARIABLE(grub_relocator_xen_remap_start)
+LOCAL(base):
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remapper_virt)
+ .quad 0
+
+ movq %rax, %rdi
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remapper_map)
+ .quad 0
+
+ movq %rax, %rsi
+
+ movq $2, %rdx
+ movq $__HYPERVISOR_update_va_mapping, %rax
+ syscall
+
+ addq $(LOCAL(cont) - LOCAL(base)), %rdi
+
+ jmp *%rdi
+
+LOCAL(cont):
+
+ /* mov imm64, %rcx */
+ .byte 0x48
+ .byte 0xb9
+VARIABLE(grub_relocator_xen_paging_size)
+ .quad 0
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_paging_start)
+ .quad 0
+
+ movq %rax, %rdi
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_mfn_list)
+ .quad 0
+
+ movq %rax, %rsi
+1:
+ movq %rsi, %rbx
+ movq 0(%rsi), %rsi
+ shlq $12, %rsi
+ orq $5, %rsi
+ movq $2, %rdx
+ movq %rcx, %r9
+ movq $__HYPERVISOR_update_va_mapping, %rax
+ syscall
+
+ movq %r9, %rcx
+ addq $8, %rbx
+ addq $4096, %rdi
+ movq %rbx, %rsi
+
+ loop 1b
+
+ leaq EXT_C(grub_relocator_xen_mmu_op) (%rip), %rdi
+ movq $3, %rsi
+ movq $0, %rdx
+ movq $0x7FF0, %r10
+ movq $__HYPERVISOR_mmuext_op, %rax
+ syscall
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remap_continue)
+ .quad 0
+
+ jmp *%rax
+
+VARIABLE(grub_relocator_xen_mmu_op)
+ .space 256
+
+VARIABLE(grub_relocator_xen_remap_end)
+
+
+VARIABLE(grub_relocator_xen_start)
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_remapper_virt2)
+ .quad 0
+
+ movq %rax, %rdi
+
+ xorq %rax, %rax
+ movq %rax, %rsi
+
+ movq $2, %rdx
+ movq $__HYPERVISOR_update_va_mapping, %rax
+ syscall
+
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_stack)
+ .quad 0
+
+ movq %rax, %rsp
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_start_info)
+ .quad 0
+
+ movq %rax, %rsi
+
+ cld
+
+ /* mov imm64, %rax */
+ .byte 0x48
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_entry_point)
+ .quad 0
+
+ jmp *%rax
+
+VARIABLE(grub_relocator_xen_end)
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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 <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/xen.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+grub_err_t
+grub_get_datetime (struct grub_datetime *datetime)
+{
+ long long nix;
+ nix = (grub_xen_shared_info->wc_sec
+ + grub_divmod64 (grub_xen_shared_info->vcpu_info[0].time.system_time, 1000000000, 0));
+ grub_unixtime2datetime (nix, datetime);
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_set_datetime (struct grub_datetime *datetime __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_IO, "setting time isn't supported");
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/mm.h>
+#include <grub/misc.h>
+#include <grub/kernel.h>
+#include <grub/xen.h>
+
+void
+grub_halt (void)
+{
+ struct sched_shutdown arg;
+
+ arg.reason = SHUTDOWN_poweroff;
+ grub_xen_sched_op (SCHEDOP_shutdown, &arg);
+ for (;;);
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/mm.h>
+#include <grub/misc.h>
+#include <grub/kernel.h>
+#include <grub/xen.h>
+
+void
+grub_reboot (void)
+{
+ struct sched_shutdown arg;
+
+ arg.reason = SHUTDOWN_reboot;
+ grub_xen_sched_op (SCHEDOP_shutdown, &arg);
+ for (;;);
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/term.h>
+#include <grub/xen.h>
+
+#include <grub/xen/relocator.h>
+#include <grub/relocator_private.h>
+
+typedef grub_addr_t grub_xen_reg_t;
+
+extern grub_uint8_t grub_relocator_xen_start;
+extern grub_uint8_t grub_relocator_xen_end;
+extern grub_uint8_t grub_relocator_xen_remap_start;
+extern grub_uint8_t grub_relocator_xen_remap_end;
+extern grub_xen_reg_t grub_relocator_xen_stack;
+extern grub_xen_reg_t grub_relocator_xen_start_info;
+extern grub_xen_reg_t grub_relocator_xen_entry_point;
+extern grub_xen_reg_t grub_relocator_xen_paging_start;
+extern grub_xen_reg_t grub_relocator_xen_paging_size;
+extern grub_xen_reg_t grub_relocator_xen_remapper_virt;
+extern grub_xen_reg_t grub_relocator_xen_remapper_virt2;
+extern grub_xen_reg_t grub_relocator_xen_remapper_map;
+extern grub_xen_reg_t grub_relocator_xen_mfn_list;
+extern grub_xen_reg_t grub_relocator_xen_remap_continue;
+#ifdef __i386__
+extern grub_xen_reg_t grub_relocator_xen_mmu_op_addr;
+extern grub_xen_reg_t grub_relocator_xen_remapper_map_high;
+#endif
+extern mmuext_op_t grub_relocator_xen_mmu_op[3];
+
+#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
+
+grub_err_t
+grub_relocator_xen_boot (struct grub_relocator *rel,
+ struct grub_relocator_xen_state state,
+ grub_uint64_t remapper_pfn,
+ grub_addr_t remapper_virt,
+ grub_uint64_t trampoline_pfn,
+ grub_addr_t trampoline_virt)
+{
+ grub_err_t err;
+ void *relst;
+ grub_relocator_chunk_t ch, ch_tramp;
+ grub_xen_mfn_t *mfn_list =
+ (grub_xen_mfn_t *) grub_xen_start_page_addr->mfn_list;
+
+ err = grub_relocator_alloc_chunk_addr (rel, &ch, remapper_pfn << 12,
+ RELOCATOR_SIZEOF (_xen_remap));
+ if (err)
+ return err;
+ err = grub_relocator_alloc_chunk_addr (rel, &ch_tramp, trampoline_pfn << 12,
+ RELOCATOR_SIZEOF (_xen));
+ if (err)
+ return err;
+
+ grub_relocator_xen_stack = state.stack;
+ grub_relocator_xen_start_info = state.start_info;
+ grub_relocator_xen_entry_point = state.entry_point;
+ grub_relocator_xen_paging_start = state.paging_start << 12;
+ grub_relocator_xen_paging_size = state.paging_size;
+ grub_relocator_xen_remapper_virt = remapper_virt;
+ grub_relocator_xen_remapper_virt2 = remapper_virt;
+ grub_relocator_xen_remap_continue = trampoline_virt;
+
+ grub_relocator_xen_remapper_map = (mfn_list[remapper_pfn] << 12) | 5;
+#ifdef __i386__
+ grub_relocator_xen_remapper_map_high = (mfn_list[remapper_pfn] >> 20);
+ grub_relocator_xen_mmu_op_addr = (char *) &grub_relocator_xen_mmu_op
+ - (char *) &grub_relocator_xen_remap_start + remapper_virt;
+#endif
+
+ grub_relocator_xen_mfn_list = state.mfn_list
+ + state.paging_start * sizeof (grub_addr_t);
+
+ grub_memset (grub_relocator_xen_mmu_op, 0,
+ sizeof (grub_relocator_xen_mmu_op));
+#ifdef __i386__
+ grub_relocator_xen_mmu_op[0].cmd = MMUEXT_PIN_L3_TABLE;
+#else
+ grub_relocator_xen_mmu_op[0].cmd = MMUEXT_PIN_L4_TABLE;
+#endif
+ grub_relocator_xen_mmu_op[0].arg1.mfn = mfn_list[state.paging_start];
+ grub_relocator_xen_mmu_op[1].cmd = MMUEXT_NEW_BASEPTR;
+ grub_relocator_xen_mmu_op[1].arg1.mfn = mfn_list[state.paging_start];
+ grub_relocator_xen_mmu_op[2].cmd = MMUEXT_UNPIN_TABLE;
+ grub_relocator_xen_mmu_op[2].arg1.mfn =
+ mfn_list[grub_xen_start_page_addr->pt_base >> 12];
+
+ grub_memmove (get_virtual_current_address (ch),
+ &grub_relocator_xen_remap_start,
+ RELOCATOR_SIZEOF (_xen_remap));
+ grub_memmove (get_virtual_current_address (ch_tramp),
+ &grub_relocator_xen_start, RELOCATOR_SIZEOF (_xen));
+
+ err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch),
+ &relst, NULL);
+ if (err)
+ return err;
+
+ ((void (*)(void)) relst) ();
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+#include <grub/cpu/linux.h>
+#include <grub/video.h>
+#include <grub/video_fb.h>
+#include <grub/command.h>
+#include <grub/xen/relocator.h>
+#include <grub/i18n.h>
+#include <grub/elf.h>
+#include <grub/elfload.h>
+#include <grub/lib/cmdline.h>
+#include <grub/xen.h>
+#include <grub/xen_file.h>
+#include <grub/linux.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static struct grub_relocator *relocator = NULL;
+static grub_uint64_t max_addr;
+static grub_dl_t my_mod;
+static int loaded = 0;
+static struct start_info next_start;
+static void *kern_chunk_src;
+static struct grub_xen_file_info xen_inf;
+static struct xen_multiboot_mod_list *xen_module_info_page;
+static grub_uint64_t modules_target_start;
+static grub_size_t n_modules;
+
+#define PAGE_SIZE 4096
+#define MAX_MODULES (PAGE_SIZE / sizeof (struct xen_multiboot_mod_list))
+#define PAGE_SHIFT 12
+#define STACK_SIZE 1048576
+#define ADDITIONAL_SIZE (1 << 19)
+#define ALIGN_SIZE (1 << 22)
+#define LOG_POINTERS_PER_PAGE 9
+#define POINTERS_PER_PAGE (1 << LOG_POINTERS_PER_PAGE)
+
+static grub_uint64_t
+page2offset (grub_uint64_t page)
+{
+ return page << PAGE_SHIFT;
+}
+
+#ifdef __x86_64__
+#define NUMBER_OF_LEVELS 4
+#define INTERMEDIATE_OR 7
+#else
+#define NUMBER_OF_LEVELS 3
+#define INTERMEDIATE_OR 3
+#endif
+
+static grub_uint64_t
+get_pgtable_size (grub_uint64_t total_pages, grub_uint64_t virt_base)
+{
+ if (!virt_base)
+ total_pages++;
+ grub_uint64_t ret = 0;
+ grub_uint64_t ll = total_pages;
+ int i;
+ for (i = 0; i < NUMBER_OF_LEVELS; i++)
+ {
+ ll = (ll + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
+ /* PAE wants all 4 root directories present. */
+#ifdef __i386__
+ if (i == 1)
+ ll = 4;
+#endif
+ ret += ll;
+ }
+ for (i = 1; i < NUMBER_OF_LEVELS; i++)
+ if (virt_base >> (PAGE_SHIFT + i * LOG_POINTERS_PER_PAGE))
+ ret++;
+ return ret;
+}
+
+static void
+generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
+ grub_uint64_t total_pages, grub_uint64_t virt_base,
+ grub_xen_mfn_t *mfn_list)
+{
+ if (!virt_base)
+ total_pages++;
+
+ grub_uint64_t lx[NUMBER_OF_LEVELS], lxs[NUMBER_OF_LEVELS];
+ grub_uint64_t nlx, nls, sz = 0;
+ int l;
+
+ nlx = total_pages;
+ nls = virt_base >> PAGE_SHIFT;
+ for (l = 0; l < NUMBER_OF_LEVELS; l++)
+ {
+ nlx = (nlx + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
+ /* PAE wants all 4 root directories present. */
+#ifdef __i386__
+ if (l == 1)
+ nlx = 4;
+#endif
+ lx[l] = nlx;
+ sz += lx[l];
+ lxs[l] = nls & (POINTERS_PER_PAGE - 1);
+ if (nls && l != 0)
+ sz++;
+ nls >>= LOG_POINTERS_PER_PAGE;
+ }
+
+ grub_uint64_t lp;
+ grub_uint64_t j;
+ grub_uint64_t *pg = (grub_uint64_t *) where;
+ int pr = 0;
+
+ grub_memset (pg, 0, sz * PAGE_SIZE);
+
+ lp = paging_start + lx[NUMBER_OF_LEVELS - 1];
+ for (l = NUMBER_OF_LEVELS - 1; l >= 1; l--)
+ {
+ if (lxs[l] || pr)
+ pg[0] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
+ if (pr)
+ pg += POINTERS_PER_PAGE;
+ for (j = 0; j < lx[l - 1]; j++)
+ pg[j + lxs[l]] = page2offset (mfn_list[lp++]) | INTERMEDIATE_OR;
+ pg += lx[l] * POINTERS_PER_PAGE;
+ if (lxs[l])
+ pr = 1;
+ }
+
+ if (lxs[0] || pr)
+ pg[0] = page2offset (mfn_list[total_pages]) | 5;
+ if (pr)
+ pg += POINTERS_PER_PAGE;
+
+ for (j = 0; j < total_pages; j++)
+ {
+ if (j >= paging_start && j < lp)
+ pg[j + lxs[0]] = page2offset (mfn_list[j]) | 5;
+ else
+ pg[j + lxs[0]] = page2offset (mfn_list[j]) | 7;
+ }
+}
+
+static grub_err_t
+set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
+{
+ grub_xen_mfn_t i, t;
+ grub_xen_mfn_t cn_pfn = -1, st_pfn = -1;
+ struct mmu_update m2p_updates[4];
+
+
+ for (i = 0; i < grub_xen_start_page_addr->nr_pages; i++)
+ {
+ if (new_mfn_list[i] == grub_xen_start_page_addr->console.domU.mfn)
+ cn_pfn = i;
+ if (new_mfn_list[i] == grub_xen_start_page_addr->store_mfn)
+ st_pfn = i;
+ }
+ if (cn_pfn == (grub_xen_mfn_t)-1)
+ return grub_error (GRUB_ERR_BUG, "no console");
+ if (st_pfn == (grub_xen_mfn_t)-1)
+ return grub_error (GRUB_ERR_BUG, "no store");
+ t = new_mfn_list[pfn];
+ new_mfn_list[pfn] = new_mfn_list[cn_pfn];
+ new_mfn_list[cn_pfn] = t;
+ t = new_mfn_list[pfn + 1];
+ new_mfn_list[pfn + 1] = new_mfn_list[st_pfn];
+ new_mfn_list[st_pfn] = t;
+
+ m2p_updates[0].ptr = page2offset (new_mfn_list[pfn]) | MMU_MACHPHYS_UPDATE;
+ m2p_updates[0].val = pfn;
+ m2p_updates[1].ptr =
+ page2offset (new_mfn_list[pfn + 1]) | MMU_MACHPHYS_UPDATE;
+ m2p_updates[1].val = pfn + 1;
+ m2p_updates[2].ptr =
+ page2offset (new_mfn_list[cn_pfn]) | MMU_MACHPHYS_UPDATE;
+ m2p_updates[2].val = cn_pfn;
+ m2p_updates[3].ptr =
+ page2offset (new_mfn_list[st_pfn]) | MMU_MACHPHYS_UPDATE;
+ m2p_updates[3].val = st_pfn;
+
+ grub_xen_mmu_update (m2p_updates, 4, NULL, DOMID_SELF);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_xen_boot (void)
+{
+ struct grub_relocator_xen_state state;
+ grub_relocator_chunk_t ch;
+ grub_err_t err;
+ grub_size_t pgtsize;
+ struct start_info *nst;
+ grub_uint64_t nr_info_pages;
+ grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
+ struct gnttab_set_version gnttab_setver;
+ grub_xen_mfn_t *new_mfn_list;
+ grub_size_t i;
+
+ if (grub_xen_n_allocated_shared_pages)
+ return grub_error (GRUB_ERR_BUG, "active grants");
+
+ state.mfn_list = max_addr;
+ next_start.mfn_list = max_addr + xen_inf.virt_base;
+ next_start.first_p2m_pfn = max_addr >> PAGE_SHIFT; /* Is this right? */
+ pgtsize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, pgtsize);
+ next_start.nr_p2m_frames = (pgtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ if (err)
+ return err;
+ new_mfn_list = get_virtual_current_address (ch);
+ grub_memcpy (new_mfn_list,
+ (void *) grub_xen_start_page_addr->mfn_list, pgtsize);
+ max_addr = ALIGN_UP (max_addr + pgtsize, PAGE_SIZE);
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ max_addr, sizeof (next_start));
+ if (err)
+ return err;
+ state.start_info = max_addr + xen_inf.virt_base;
+ nst = get_virtual_current_address (ch);
+ max_addr = ALIGN_UP (max_addr + sizeof (next_start), PAGE_SIZE);
+
+ next_start.nr_pages = grub_xen_start_page_addr->nr_pages;
+ grub_memcpy (next_start.magic, grub_xen_start_page_addr->magic,
+ sizeof (next_start.magic));
+ next_start.store_mfn = grub_xen_start_page_addr->store_mfn;
+ next_start.store_evtchn = grub_xen_start_page_addr->store_evtchn;
+ next_start.console.domU = grub_xen_start_page_addr->console.domU;
+ next_start.shared_info = grub_xen_start_page_addr->shared_info;
+
+ err = set_mfns (new_mfn_list, max_addr >> PAGE_SHIFT);
+ if (err)
+ return err;
+ max_addr += 2 * PAGE_SIZE;
+
+ next_start.pt_base = max_addr + xen_inf.virt_base;
+ state.paging_start = max_addr >> PAGE_SHIFT;
+
+ nr_info_pages = max_addr >> PAGE_SHIFT;
+ nr_pages = nr_info_pages;
+
+ while (1)
+ {
+ nr_pages = ALIGN_UP (nr_pages, (ALIGN_SIZE >> PAGE_SHIFT));
+ nr_pt_pages = get_pgtable_size (nr_pages, xen_inf.virt_base);
+ nr_need_pages =
+ nr_info_pages + nr_pt_pages +
+ ((ADDITIONAL_SIZE + STACK_SIZE) >> PAGE_SHIFT);
+ if (nr_pages >= nr_need_pages)
+ break;
+ nr_pages = nr_need_pages;
+ }
+
+ grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
+ (unsigned long long) xen_inf.virt_base,
+ (unsigned long long) page2offset (nr_pages));
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ max_addr, page2offset (nr_pt_pages));
+ if (err)
+ return err;
+
+ generate_page_table (get_virtual_current_address (ch),
+ max_addr >> PAGE_SHIFT, nr_pages,
+ xen_inf.virt_base, new_mfn_list);
+
+ max_addr += page2offset (nr_pt_pages);
+ state.stack = max_addr + STACK_SIZE + xen_inf.virt_base;
+ state.entry_point = xen_inf.entry_point;
+
+ next_start.nr_p2m_frames += nr_pt_pages;
+ next_start.nr_pt_frames = nr_pt_pages;
+ state.paging_size = nr_pt_pages;
+
+ *nst = next_start;
+
+ grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
+
+ gnttab_setver.version = 1;
+ grub_xen_grant_table_op (GNTTABOP_set_version, &gnttab_setver, 1);
+
+ for (i = 0; i < ARRAY_SIZE (grub_xen_shared_info->evtchn_pending); i++)
+ grub_xen_shared_info->evtchn_pending[i] = 0;
+
+ return grub_relocator_xen_boot (relocator, state, nr_pages,
+ xen_inf.virt_base <
+ PAGE_SIZE ? page2offset (nr_pages) : 0,
+ nr_pages - 1,
+ page2offset (nr_pages - 1) +
+ xen_inf.virt_base);
+}
+
+static grub_err_t
+grub_xen_unload (void)
+{
+ grub_dl_unref (my_mod);
+ loaded = 0;
+ return GRUB_ERR_NONE;
+}
+
+#define HYPERCALL_INTERFACE_SIZE 32
+
+#ifdef __x86_64__
+static grub_uint8_t template[] =
+ {
+ 0x51, /* push %rcx */
+ 0x41, 0x53, /* push %r11 */
+ 0x48, 0xc7, 0xc0, 0xbb, 0xaa, 0x00, 0x00, /* mov $0xaabb,%rax */
+ 0x0f, 0x05, /* syscall */
+ 0x41, 0x5b, /* pop %r11 */
+ 0x59, /* pop %rcx */
+ 0xc3 /* ret */
+ };
+
+static grub_uint8_t template_iret[] =
+ {
+ 0x51, /* push %rcx */
+ 0x41, 0x53, /* push %r11 */
+ 0x50, /* push %rax */
+ 0x48, 0xc7, 0xc0, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%rax */
+ 0x0f, 0x05 /* syscall */
+ };
+#define CALLNO_OFFSET 6
+#else
+
+static grub_uint8_t template[] =
+ {
+ 0xb8, 0xbb, 0xaa, 0x00, 0x00, /* mov imm32, %eax */
+ 0xcd, 0x82, /* int $0x82 */
+ 0xc3 /* ret */
+ };
+
+static grub_uint8_t template_iret[] =
+ {
+ 0x50, /* push %eax */
+ 0xb8, 0x17, 0x00, 0x00, 0x00, /* mov $0x17,%eax */
+ 0xcd, 0x82, /* int $0x82 */
+ };
+#define CALLNO_OFFSET 1
+
+#endif
+
+
+static void
+set_hypercall_interface (grub_uint8_t *tgt, unsigned callno)
+{
+ if (callno == 0x17)
+ {
+ grub_memcpy (tgt, template_iret, ARRAY_SIZE (template_iret));
+ grub_memset (tgt + ARRAY_SIZE (template_iret), 0xcc,
+ HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template_iret));
+ return;
+ }
+ grub_memcpy (tgt, template, ARRAY_SIZE (template));
+ grub_memset (tgt + ARRAY_SIZE (template), 0xcc,
+ HYPERCALL_INTERFACE_SIZE - ARRAY_SIZE (template));
+ tgt[CALLNO_OFFSET] = callno & 0xff;
+ tgt[CALLNO_OFFSET + 1] = callno >> 8;
+}
+
+#ifdef __x86_64__
+#define grub_elfXX_load grub_elf64_load
+#else
+#define grub_elfXX_load grub_elf32_load
+#endif
+
+static grub_err_t
+grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ grub_elf_t elf;
+ grub_err_t err;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ grub_loader_unset ();
+
+ grub_memset (&next_start, 0, sizeof (next_start));
+
+ xen_module_info_page = NULL;
+ n_modules = 0;
+
+ grub_create_loader_cmdline (argc - 1, argv + 1,
+ (char *) next_start.cmd_line,
+ sizeof (next_start.cmd_line) - 1);
+
+ file = grub_file_open (argv[0]);
+ if (!file)
+ return grub_errno;
+
+ elf = grub_xen_file (file);
+ if (!elf)
+ goto fail;
+
+ err = grub_xen_get_info (elf, &xen_inf);
+ if (err)
+ goto fail;
+#ifdef __x86_64__
+ if (xen_inf.arch != GRUB_XEN_FILE_X86_64)
+#else
+ if (xen_inf.arch != GRUB_XEN_FILE_I386_PAE
+ && xen_inf.arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+#endif
+ {
+ grub_error (GRUB_ERR_BAD_OS, "incompatible architecture: %d",
+ xen_inf.arch);
+ goto fail;
+ }
+
+ if (xen_inf.virt_base & (PAGE_SIZE - 1))
+ {
+ grub_error (GRUB_ERR_BAD_OS, "unaligned virt_base");
+ goto fail;
+ }
+ grub_dprintf ("xen", "virt_base = %llx, entry = %llx\n",
+ (unsigned long long) xen_inf.virt_base,
+ (unsigned long long) xen_inf.entry_point);
+
+ relocator = grub_relocator_new ();
+ if (!relocator)
+ goto fail;
+
+ grub_relocator_chunk_t ch;
+ grub_addr_t kern_start = xen_inf.kern_start - xen_inf.paddr_offset;
+ grub_addr_t kern_end = xen_inf.kern_end - xen_inf.paddr_offset;
+
+ if (xen_inf.has_hypercall_page)
+ {
+ grub_dprintf ("xen", "hypercall page at 0x%llx\n",
+ (unsigned long long) xen_inf.hypercall_page);
+ if (xen_inf.hypercall_page - xen_inf.virt_base < kern_start)
+ kern_start = xen_inf.hypercall_page - xen_inf.virt_base;
+
+ if (xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE > kern_end)
+ kern_end = xen_inf.hypercall_page - xen_inf.virt_base + PAGE_SIZE;
+ }
+
+ max_addr = ALIGN_UP (kern_end, PAGE_SIZE);
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
+ kern_end - kern_start);
+ if (err)
+ goto fail;
+ kern_chunk_src = get_virtual_current_address (ch);
+
+ grub_dprintf ("xen", "paddr_offset = 0x%llx\n",
+ (unsigned long long) xen_inf.paddr_offset);
+ grub_dprintf ("xen", "kern_start = 0x%llx, kern_end = 0x%llx\n",
+ (unsigned long long) xen_inf.kern_start,
+ (unsigned long long) xen_inf.kern_end);
+
+ err = grub_elfXX_load (elf, argv[0],
+ (grub_uint8_t *) kern_chunk_src - kern_start
+ - xen_inf.paddr_offset, 0, 0, 0);
+
+ if (xen_inf.has_hypercall_page)
+ {
+ unsigned i;
+ for (i = 0; i < PAGE_SIZE / HYPERCALL_INTERFACE_SIZE; i++)
+ set_hypercall_interface ((grub_uint8_t *) kern_chunk_src +
+ i * HYPERCALL_INTERFACE_SIZE +
+ xen_inf.hypercall_page - xen_inf.virt_base -
+ kern_start, i);
+ }
+
+ if (err)
+ goto fail;
+
+ grub_dl_ref (my_mod);
+ loaded = 1;
+
+ grub_loader_set (grub_xen_boot, grub_xen_unload, 0);
+ loaded = 1;
+
+ goto fail;
+
+fail:
+
+ if (elf)
+ grub_elf_close (elf);
+ else if (file)
+ grub_file_close (file);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ loaded = 0;
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_size_t size = 0;
+ grub_err_t err;
+ struct grub_linux_initrd_context initrd_ctx;
+ grub_relocator_chunk_t ch;
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ goto fail;
+ }
+
+ if (!loaded)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+ goto fail;
+ }
+
+ if (next_start.mod_start || next_start.mod_len)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
+ goto fail;
+ }
+
+ if (grub_initrd_init (argc, argv, &initrd_ctx))
+ goto fail;
+
+ size = grub_get_initrd_size (&initrd_ctx);
+
+ if (size)
+ {
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
+ if (err)
+ return err;
+
+ if (grub_initrd_load (&initrd_ctx, argv,
+ get_virtual_current_address (ch)))
+ goto fail;
+ }
+
+ next_start.mod_start = max_addr + xen_inf.virt_base;
+ next_start.mod_len = size;
+
+ max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
+
+ grub_dprintf ("xen", "Initrd, addr=0x%x, size=0x%x\n",
+ (unsigned) next_start.mod_start, (unsigned) size);
+
+fail:
+ grub_initrd_close (&initrd_ctx);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_size_t size = 0;
+ grub_err_t err;
+ grub_relocator_chunk_t ch;
+ grub_size_t cmdline_len;
+ int nounzip = 0;
+ grub_file_t file;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ if (grub_strcmp (argv[0], "--nounzip") == 0)
+ {
+ argv++;
+ argc--;
+ nounzip = 1;
+ }
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ if (!loaded)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+ }
+
+ if ((next_start.mod_start || next_start.mod_len) && !xen_module_info_page)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
+ }
+
+ /* Leave one space for terminator. */
+ if (n_modules >= MAX_MODULES - 1)
+ {
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many modules");
+ }
+
+ if (!xen_module_info_page)
+ {
+ n_modules = 0;
+ max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
+ modules_target_start = max_addr;
+ next_start.mod_start = max_addr + xen_inf.virt_base;
+ next_start.flags |= SIF_MULTIBOOT_MOD;
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ max_addr, MAX_MODULES
+ *
+ sizeof (xen_module_info_page
+ [0]));
+ if (err)
+ return err;
+ xen_module_info_page = get_virtual_current_address (ch);
+ grub_memset (xen_module_info_page, 0, MAX_MODULES
+ * sizeof (xen_module_info_page[0]));
+ max_addr += MAX_MODULES * sizeof (xen_module_info_page[0]);
+ }
+
+ max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
+
+ if (nounzip)
+ grub_file_filter_disable_compression ();
+ file = grub_file_open (argv[0]);
+ if (!file)
+ return grub_errno;
+ size = grub_file_size (file);
+
+ cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1);
+
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ max_addr, cmdline_len);
+ if (err)
+ goto fail;
+
+ grub_create_loader_cmdline (argc - 1, argv + 1,
+ get_virtual_current_address (ch), cmdline_len);
+
+ xen_module_info_page[n_modules].cmdline = max_addr - modules_target_start;
+ max_addr = ALIGN_UP (max_addr + cmdline_len, PAGE_SIZE);
+
+ if (size)
+ {
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
+ if (err)
+ goto fail;
+ if (grub_file_read (file, get_virtual_current_address (ch), size)
+ != (grub_ssize_t) size)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_FILE_READ_ERROR,
+ N_("premature end of file %s"), argv[0]);
+ goto fail;
+ }
+ }
+ next_start.mod_len = max_addr + size - modules_target_start;
+ xen_module_info_page[n_modules].mod_start = max_addr - modules_target_start;
+ xen_module_info_page[n_modules].mod_end =
+ max_addr + size - modules_target_start;
+
+ n_modules++;
+ grub_dprintf ("xen", "module, addr=0x%x, size=0x%x\n",
+ (unsigned) max_addr, (unsigned) size);
+ max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
+
+
+fail:
+ grub_file_close (file);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd_xen, cmd_initrd, cmd_module, cmd_multiboot;
+
+GRUB_MOD_INIT (xen)
+{
+ cmd_xen = grub_register_command ("linux", grub_cmd_xen,
+ 0, N_("Load linux."));
+ cmd_multiboot = grub_register_command ("multiboot", grub_cmd_xen,
+ 0, N_("Load linux."));
+ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
+ 0, N_("Load initrd."));
+ cmd_module = grub_register_command ("module", grub_cmd_module,
+ 0, N_("Load module."));
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI (xen)
+{
+ grub_unregister_command (cmd_xen);
+ grub_unregister_command (cmd_initrd);
+ grub_unregister_command (cmd_multiboot);
+ grub_unregister_command (cmd_module);
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/xen_file.h>
+#include <grub/i386/linux.h>
+
+grub_elf_t
+grub_xen_file (grub_file_t file)
+{
+ grub_elf_t elf;
+ struct linux_kernel_header lh;
+ grub_file_t off_file;
+
+ elf = grub_elf_file (file, file->name);
+ if (elf)
+ return elf;
+ grub_errno = GRUB_ERR_NONE;
+
+ if (grub_file_seek (file, 0) == (grub_off_t) -1)
+ goto fail;
+
+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ goto fail;
+
+ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)
+ || lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE)
+ || grub_le_to_cpu16 (lh.version) < 0x0208)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "version too old for xen boot");
+ return NULL;
+ }
+
+ if (lh.payload_length < 4)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "payload too short");
+ return NULL;
+ }
+
+ grub_dprintf ("xen", "found bzimage payload 0x%llx-0x%llx\n",
+ (unsigned long long) (lh.setup_sects + 1) * 512
+ + lh.payload_offset,
+ (unsigned long long) lh.payload_length - 4);
+
+ off_file = grub_file_offset_open (file, (lh.setup_sects + 1) * 512
+ + lh.payload_offset,
+ lh.payload_length - 4);
+ if (!off_file)
+ goto fail;
+
+ elf = grub_elf_file (off_file, file->name);
+ if (elf)
+ return elf;
+ grub_file_offset_close (off_file);
+
+fail:
+ grub_error (GRUB_ERR_BAD_OS, "not xen image");
+ return NULL;
+}
+
+grub_err_t
+grub_xen_get_info (grub_elf_t elf, struct grub_xen_file_info * xi)
+{
+ grub_memset (xi, 0, sizeof (*xi));
+
+ if (grub_elf_is_elf64 (elf))
+ {
+ xi->arch = GRUB_XEN_FILE_X86_64;
+ return grub_xen_get_info64 (elf, xi);
+ }
+ if (grub_elf_is_elf32 (elf))
+ {
+ xi->arch = GRUB_XEN_FILE_I386;
+ return grub_xen_get_info32 (elf, xi);
+ }
+ return grub_error (GRUB_ERR_BAD_OS, "unknown ELF type");
+}
--- /dev/null
+#define GRUB_TARGET_WORDSIZE 32
+#define XX 32
+#define grub_le_to_cpu_addr grub_le_to_cpu32
+#define ehdrXX ehdr32
+#define grub_xen_get_infoXX grub_xen_get_info32
+#define FOR_ELF_PHDRS FOR_ELF32_PHDRS
+#include "xen_fileXX.c"
--- /dev/null
+#define GRUB_TARGET_WORDSIZE 64
+#define XX 64
+#define grub_le_to_cpu_addr grub_le_to_cpu64
+#define ehdrXX ehdr64
+#define grub_xen_get_infoXX grub_xen_get_info64
+#define FOR_ELF_PHDRS FOR_ELF64_PHDRS
+#include "xen_fileXX.c"
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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/xen_file.h>
+
+static grub_err_t
+parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
+ grub_off_t off, grub_size_t sz)
+{
+ char *buf;
+ char *ptr;
+ int has_paddr = 0;
+ if (grub_file_seek (elf->file, off) == (grub_off_t) -1)
+ return grub_errno;
+ buf = grub_malloc (sz);
+ if (!buf)
+ return grub_errno;
+
+ if (grub_file_read (elf->file, buf, sz) != (grub_ssize_t) sz)
+ {
+ if (grub_errno)
+ return grub_errno;
+ return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ elf->file->name);
+ }
+ xi->has_xen_guest = 1;
+ for (ptr = buf; ptr && ptr - buf < (grub_ssize_t) sz;
+ ptr = grub_strchr (ptr, ','), (ptr ? ptr++ : 0))
+ {
+ if (grub_strncmp (ptr, "PAE=no,", sizeof ("PAE=no,") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=yes,", sizeof ("PAE=yes,") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=yes[extended-cr3],",
+ sizeof ("PAE=yes[extended-cr3],") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE;
+ xi->extended_cr3 = 1;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=bimodal,", sizeof ("PAE=bimodal,") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=bimodal[extended-cr3],",
+ sizeof ("PAE=bimodal[extended-cr3],") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ xi->extended_cr3 = 1;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=yes,bimodal,", sizeof ("PAE=yes,bimodal,") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "PAE=yes[extended-cr3],bimodal,",
+ sizeof ("PAE=yes[extended-cr3],bimodal,") - 1) == 0)
+ {
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ continue;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ xi->extended_cr3 = 1;
+ continue;
+ }
+
+ if (grub_strncmp (ptr, "VIRT_BASE=", sizeof ("VIRT_BASE=") - 1) == 0)
+ {
+ xi->virt_base = grub_strtoull (ptr + sizeof ("VIRT_BASE=") - 1, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ continue;
+ }
+ if (grub_strncmp (ptr, "VIRT_ENTRY=", sizeof ("VIRT_ENTRY=") - 1) == 0)
+ {
+ xi->entry_point = grub_strtoull (ptr + sizeof ("VIRT_ENTRY=") - 1, &ptr, 16);
+ if (grub_errno)
+ return grub_errno;
+ continue;
+ }
+ if (grub_strncmp (ptr, "HYPERCALL_PAGE=", sizeof ("HYPERCALL_PAGE=") - 1) == 0)
+ {
+ xi->hypercall_page = grub_strtoull (ptr + sizeof ("HYPERCALL_PAGE=") - 1, &ptr, 16);
+ xi->has_hypercall_page = 1;
+ if (grub_errno)
+ return grub_errno;
+ continue;
+ }
+ if (grub_strncmp (ptr, "ELF_PADDR_OFFSET=", sizeof ("ELF_PADDR_OFFSET=") - 1) == 0)
+ {
+ xi->paddr_offset = grub_strtoull (ptr + sizeof ("ELF_PADDR_OFFSET=") - 1, &ptr, 16);
+ has_paddr = 1;
+ if (grub_errno)
+ return grub_errno;
+ continue;
+ }
+ }
+ if (xi->has_hypercall_page)
+ xi->hypercall_page = (xi->hypercall_page << 12) + xi->virt_base;
+ if (!has_paddr)
+ xi->paddr_offset = xi->virt_base;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+parse_note (grub_elf_t elf, struct grub_xen_file_info *xi,
+ grub_off_t off, grub_size_t sz)
+{
+ grub_uint32_t *buf;
+ grub_uint32_t *ptr;
+ if (grub_file_seek (elf->file, off) == (grub_off_t) -1)
+ return grub_errno;
+ buf = grub_malloc (sz);
+ if (!buf)
+ return grub_errno;
+
+ if (grub_file_read (elf->file, buf, sz) != (grub_ssize_t) sz)
+ {
+ if (grub_errno)
+ return grub_errno;
+ return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ elf->file->name);
+ }
+ for (ptr = buf; ptr - buf < (grub_ssize_t) (sz / sizeof (grub_uint32_t));)
+ {
+ Elf_Nhdr *nh = (Elf_Nhdr *) ptr;
+ char *name;
+ grub_uint32_t *desc;
+ grub_uint32_t namesz, descsz;
+ ptr += sizeof (*nh) / sizeof (grub_uint32_t);
+ name = (char *) ptr;
+ namesz = grub_le_to_cpu32 (nh->n_namesz);
+ descsz = grub_le_to_cpu32 (nh->n_descsz);
+ ptr += (namesz + 3) / 4;
+ desc = ptr;
+ ptr += (grub_le_to_cpu32 (nh->n_descsz) + 3) / 4;
+ if ((namesz < 3) || grub_memcmp (name, "Xen", namesz == 3 ? 3 : 4) != 0)
+ continue;
+ xi->has_note = 1;
+ switch (nh->n_type)
+ {
+ case 1:
+ xi->entry_point = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
+ break;
+ case 2:
+ xi->hypercall_page = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
+ xi->has_hypercall_page = 1;
+ break;
+ case 3:
+ xi->virt_base = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
+ break;
+ case 4:
+ xi->paddr_offset = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
+ break;
+ case 5:
+ grub_dprintf ("xen", "xenversion = `%s'\n", (char *) desc);
+ break;
+ case 6:
+ grub_dprintf ("xen", "name = `%s'\n", (char *) desc);
+ break;
+ case 7:
+ grub_dprintf ("xen", "version = `%s'\n", (char *) desc);
+ break;
+ case 8:
+ if (descsz < 7
+ || grub_memcmp (desc, "generic", descsz == 7 ? 7 : 8) != 0)
+ return grub_error (GRUB_ERR_BAD_OS, "invalid loader");
+ break;
+ /* PAE */
+ case 9:
+ grub_dprintf ("xen", "pae = `%s', %d, %d\n", (char *) desc,
+ xi->arch, descsz);
+ if (xi->arch != GRUB_XEN_FILE_I386
+ && xi->arch != GRUB_XEN_FILE_I386_PAE
+ && xi->arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
+ break;
+ if (descsz >= 3 && grub_memcmp (desc, "yes",
+ descsz == 3 ? 3 : 4) == 0)
+ {
+ xi->extended_cr3 = 1;
+ xi->arch = GRUB_XEN_FILE_I386_PAE;
+ }
+ if (descsz >= 7 && grub_memcmp (desc, "bimodal",
+ descsz == 7 ? 7 : 8) == 0)
+ {
+ xi->extended_cr3 = 1;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ }
+ if (descsz >= 11 && grub_memcmp (desc, "yes,bimodal",
+ descsz == 11 ? 11 : 12) == 0)
+ {
+ xi->extended_cr3 = 1;
+ xi->arch = GRUB_XEN_FILE_I386_PAE_BIMODE;
+ }
+ if (descsz >= 2 && grub_memcmp (desc, "no",
+ descsz == 2 ? 2 : 3) == 0)
+ xi->arch = GRUB_XEN_FILE_I386;
+ break;
+ default:
+ grub_dprintf ("xen", "unknown note type %d\n", nh->n_type);
+ break;
+ }
+ }
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_xen_get_infoXX (grub_elf_t elf, struct grub_xen_file_info *xi)
+{
+ Elf_Shdr *s, *s0;
+ grub_size_t shnum = elf->ehdr.ehdrXX.e_shnum;
+ grub_size_t shentsize = elf->ehdr.ehdrXX.e_shentsize;
+ grub_size_t shsize = shnum * shentsize;
+ grub_off_t stroff;
+ grub_err_t err;
+ Elf_Phdr *phdr;
+
+ xi->kern_end = 0;
+ xi->kern_start = ~0;
+ xi->entry_point = elf->ehdr.ehdrXX.e_entry;
+
+ /* FIXME: check note. */
+ FOR_ELF_PHDRS (elf, phdr)
+ {
+ Elf_Addr paddr;
+
+ if (phdr->p_type == PT_NOTE)
+ {
+ err = parse_note (elf, xi, phdr->p_offset, phdr->p_filesz);
+ if (err)
+ return err;
+ }
+
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ paddr = phdr->p_paddr;
+
+ if (paddr < xi->kern_start)
+ xi->kern_start = paddr;
+
+ if (paddr + phdr->p_memsz > xi->kern_end)
+ xi->kern_end = paddr + phdr->p_memsz;
+ }
+
+ if (xi->has_note)
+ return GRUB_ERR_NONE;
+
+ if (!shnum || !shentsize)
+ return grub_error (GRUB_ERR_BAD_OS, "no XEN note");
+
+ s0 = grub_malloc (shsize);
+ if (!s0)
+ return grub_errno;
+
+ if (grub_file_seek (elf->file, elf->ehdr.ehdrXX.e_shoff) == (grub_off_t) -1)
+ return grub_errno;
+
+ if (grub_file_read (elf->file, s0, shsize) != (grub_ssize_t) shsize)
+ {
+ if (grub_errno)
+ return grub_errno;
+ return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ elf->file->name);
+ }
+
+ s = (Elf_Shdr *) ((char *) s0 + elf->ehdr.ehdrXX.e_shstrndx * shentsize);
+ stroff = s->sh_offset;
+
+ for (s = s0; s < (Elf_Shdr *) ((char *) s0 + shnum * shentsize);
+ s = (Elf_Shdr *) ((char *) s + shentsize))
+ {
+ char name[sizeof("__xen_guest")];
+ grub_memset (name, 0, sizeof (name));
+ if (grub_file_seek (elf->file, stroff + s->sh_name) == (grub_off_t) -1)
+ return grub_errno;
+
+ if (grub_file_read (elf->file, name, sizeof (name)) != (grub_ssize_t) sizeof (name))
+ {
+ if (grub_errno)
+ return grub_errno;
+ continue;
+ }
+ if (grub_memcmp (name, "__xen_guest",
+ sizeof("__xen_guest")) != 0)
+ continue;
+ return parse_xen_guest (elf, xi, s->sh_offset, s->sh_size);
+ }
+ return grub_error (GRUB_ERR_BAD_OS, "no XEN note found");
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011 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/term.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/time.h>
+#include <grub/terminfo.h>
+#include <grub/xen.h>
+
+static int
+readkey (struct grub_term_input *term __attribute__ ((unused)))
+{
+ grub_size_t prod, cons;
+ int r;
+ mb ();
+ prod = grub_xen_xcons->in_prod;
+ cons = grub_xen_xcons->in_cons;
+ if (prod <= cons)
+ return -1;
+ r = grub_xen_xcons->in[cons];
+ cons++;
+ mb ();
+ grub_xen_xcons->in_cons = cons;
+ return r;
+}
+
+static int signal_sent = 1;
+
+static void
+refresh (struct grub_term_output *term __attribute__ ((unused)))
+{
+ struct evtchn_send send;
+ send.port = grub_xen_start_page_addr->console.domU.evtchn;
+ grub_xen_event_channel_op (EVTCHNOP_send, &send);
+ signal_sent = 1;
+ while (grub_xen_xcons->out_prod != grub_xen_xcons->out_cons)
+ {
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ }
+}
+
+static void
+put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+{
+ grub_size_t prod, cons;
+
+ while (1)
+ {
+ mb ();
+ prod = grub_xen_xcons->out_prod;
+ cons = grub_xen_xcons->out_cons;
+ if (prod < cons + sizeof (grub_xen_xcons->out))
+ break;
+ if (!signal_sent)
+ refresh (term);
+ grub_xen_sched_op (SCHEDOP_yield, 0);
+ }
+ grub_xen_xcons->out[prod++ & (sizeof (grub_xen_xcons->out) - 1)] = c;
+ mb ();
+ grub_xen_xcons->out_prod = prod;
+ signal_sent = 0;
+}
+
+
+struct grub_terminfo_input_state grub_console_terminfo_input = {
+ .readkey = readkey
+};
+
+struct grub_terminfo_output_state grub_console_terminfo_output = {
+ .put = put,
+ .size = {80, 24}
+};
+
+static struct grub_term_input grub_console_term_input = {
+ .name = "console",
+ .init = 0,
+ .getkey = grub_terminfo_getkey,
+ .data = &grub_console_terminfo_input
+};
+
+static struct grub_term_output grub_console_term_output = {
+ .name = "console",
+ .init = 0,
+ .putchar = grub_terminfo_putchar,
+ .getxy = grub_terminfo_getxy,
+ .getwh = grub_terminfo_getwh,
+ .gotoxy = grub_terminfo_gotoxy,
+ .cls = grub_terminfo_cls,
+ .refresh = refresh,
+ .setcolorstate = grub_terminfo_setcolorstate,
+ .setcursor = grub_terminfo_setcursor,
+ .flags = GRUB_TERM_CODE_TYPE_ASCII,
+ .data = &grub_console_terminfo_output,
+};
+
+
+void
+grub_console_init (void)
+{
+ grub_term_register_input ("console", &grub_console_term_input);
+ grub_term_register_output ("console", &grub_console_term_output);
+
+ grub_terminfo_init ();
+ grub_terminfo_output_register (&grub_console_term_output, "vt100-color");
+}
GRUB_DISK_DEVICE_PROCFS_ID,
GRUB_DISK_DEVICE_CBFSDISK_ID,
GRUB_DISK_DEVICE_UBOOTDISK_ID,
+ GRUB_DISK_DEVICE_XEN,
};
struct grub_disk;
#if GRUB_TARGET_WORDSIZE == 32
typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Nhdr Elf_Nhdr;
typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
typedef Elf32_Half Elf_Half;
typedef Elf32_Off Elf_Off;
typedef Elf32_Rel Elf_Rel;
#elif GRUB_TARGET_WORDSIZE == 64
typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Nhdr Elf_Nhdr;
typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Half Elf_Half;
typedef Elf64_Off Elf_Off;
typedef Elf64_Rel Elf_Rel;
return !file->not_easily_seekable;
}
+grub_file_t
+grub_file_offset_open (grub_file_t parent, grub_off_t start,
+ grub_off_t size);
+void
+grub_file_offset_close (grub_file_t file);
+
#endif /* ! GRUB_FILE_HEADER */
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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_XEN_CPU_HYPERCALL_HEADER
+#define GRUB_XEN_CPU_HYPERCALL_HEADER 1
+
+#include <grub/types.h>
+
+int
+EXPORT_FUNC (grub_xen_hypercall) (grub_uint32_t callno, grub_uint32_t a0,
+ grub_uint32_t a1, grub_uint32_t a2,
+ grub_uint32_t a3, grub_uint32_t a4,
+ grub_uint32_t a5)
+__attribute__ ((regparm (3), stdcall));
+
+static inline int
+grub_xen_sched_op (int cmd, void *arg)
+{
+ return grub_xen_hypercall (__HYPERVISOR_sched_op, cmd, (grub_uint32_t) arg,
+ 0, 0, 0, 0);
+}
+
+static inline int
+grub_xen_mmu_update (const struct mmu_update *reqs,
+ unsigned count, unsigned *done_out, unsigned foreigndom)
+{
+ return grub_xen_hypercall (__HYPERVISOR_mmu_update, (grub_uint32_t) reqs,
+ (grub_uint32_t) count, (grub_uint32_t) done_out,
+ (grub_uint32_t) foreigndom, 0, 0);
+}
+
+static inline int
+grub_xen_mmuext_op (mmuext_op_t * ops,
+ unsigned int count,
+ unsigned int *pdone, unsigned int foreigndom)
+{
+ return grub_xen_hypercall (__HYPERVISOR_mmuext_op, (grub_uint32_t) ops,
+ count, (grub_uint32_t) pdone, foreigndom, 0, 0);
+}
+
+static inline int
+grub_xen_event_channel_op (int op, void *arg)
+{
+ return grub_xen_hypercall (__HYPERVISOR_event_channel_op, op,
+ (grub_uint32_t) arg, 0, 0, 0, 0);
+}
+
+
+static inline int
+grub_xen_update_va_mapping (void *addr, uint64_t pte, uint32_t flags)
+{
+ return grub_xen_hypercall (__HYPERVISOR_update_va_mapping,
+ (grub_uint32_t) addr, pte, pte >> 32, flags, 0,
+ 0);
+}
+
+static inline int
+grub_xen_grant_table_op (int a, void *b, int c)
+{
+ return grub_xen_hypercall (__HYPERVISOR_grant_table_op, a,
+ (grub_uint32_t) b, c, 0, 0, 0);
+}
+
+static inline int
+grub_xen_vm_assist (int cmd, int type)
+{
+ return grub_xen_hypercall (__HYPERVISOR_vm_assist, cmd, type, 0, 0, 0, 0);
+}
+
+#endif
#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) \
|| defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) \
|| defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_ARC) \
- || defined (__sparc__) || defined (GRUB_MACHINE_UBOOT)
+ || defined (__sparc__) || defined (GRUB_MACHINE_UBOOT) || defined (GRUB_MACHINE_XEN)
/* FIXME: stack is between 2 heap regions. Move it. */
#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 1
#endif
void grub_machine_init (void);
/* The machine-specific finalization. */
-void EXPORT_FUNC(grub_machine_fini) (void);
+void EXPORT_FUNC(grub_machine_fini) (int flags);
/* The machine-specific prefix initialization. */
void
#define GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN 0x1
#define GRUB_KERNEL_I386_MULTIBOOT_MOD_ALIGN GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN
+#define GRUB_KERNEL_X86_64_XEN_MOD_ALIGN 0x8
+#define GRUB_KERNEL_I386_XEN_MOD_ALIGN 0x8
+
/* Non-zero value is only needed for PowerMacs. */
+#define GRUB_KERNEL_X86_64_XEN_MOD_GAP 0x0
+#define GRUB_KERNEL_I386_XEN_MOD_GAP 0x0
#define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0
#define GRUB_KERNEL_I386_COREBOOT_MOD_GAP 0x0
#define GRUB_KERNEL_SPARC64_IEEE1275_MOD_GAP 0x0
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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_XEN_CPU_HYPERCALL_HEADER
+#define GRUB_XEN_CPU_HYPERCALL_HEADER 1
+
+int EXPORT_FUNC (grub_xen_sched_op) (int cmd, void *arg);
+int grub_xen_update_va_mapping (void *addr, uint64_t pte, uint64_t flags);
+int grub_xen_event_channel_op (int op, void *arg);
+
+int grub_xen_mmuext_op (mmuext_op_t * ops,
+ unsigned int count,
+ unsigned int *pdone, unsigned int foreigndom);
+int EXPORT_FUNC (grub_xen_mmu_update) (const struct mmu_update * reqs,
+ unsigned count, unsigned *done_out,
+ unsigned foreigndom);
+int EXPORT_FUNC (grub_xen_grant_table_op) (int, void *, int);
+
+#endif
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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_XEN_HEADER
+#define GRUB_XEN_HEADER 1
+
+#define __XEN_INTERFACE_VERSION__ 0x0003020a
+
+#ifdef ASM_FILE
+#define __ASSEMBLY__
+#include <xen/xen.h>
+#else
+
+#include <grub/symbol.h>
+#include <grub/types.h>
+#include <grub/err.h>
+
+#ifndef GRUB_SYMBOL_GENERATOR
+#include <stdint.h>
+#include <xen/xen.h>
+
+#include <xen/sched.h>
+#include <xen/grant_table.h>
+#include <xen/io/console.h>
+#include <xen/io/xs_wire.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/protocols.h>
+#endif
+
+#include <grub/cpu/xen/hypercall.h>
+
+extern grub_size_t EXPORT_VAR (grub_xen_n_allocated_shared_pages);
+
+
+#define GRUB_XEN_LOG_PAGE_SIZE 12
+#define GRUB_XEN_PAGE_SIZE (1 << GRUB_XEN_LOG_PAGE_SIZE)
+
+extern volatile struct xencons_interface *grub_xen_xcons;
+extern volatile struct shared_info *EXPORT_VAR (grub_xen_shared_info);
+extern volatile struct xenstore_domain_interface *grub_xen_xenstore;
+extern volatile grant_entry_v2_t *grub_xen_grant_table;
+
+void EXPORT_FUNC (grub_xen_store_send) (const void *buf_, grub_size_t len);
+void EXPORT_FUNC (grub_xen_store_recv) (void *buf_, grub_size_t len);
+grub_err_t
+EXPORT_FUNC (grub_xenstore_dir) (const char *dir,
+ int (*hook) (const char *dir,
+ void *hook_data),
+ void *hook_data);
+void *EXPORT_FUNC (grub_xenstore_get_file) (const char *dir,
+ grub_size_t * len);
+grub_err_t EXPORT_FUNC (grub_xenstore_write_file) (const char *dir,
+ const void *buf,
+ grub_size_t len);
+
+typedef unsigned int grub_xen_grant_t;
+
+void *EXPORT_FUNC (grub_xen_alloc_shared_page) (domid_t dom,
+ grub_xen_grant_t * grnum);
+void EXPORT_FUNC (grub_xen_free_shared_page) (void *ptr);
+
+#define mb() asm volatile("mfence;sfence;" : : : "memory");
+extern struct start_info *EXPORT_VAR (grub_xen_start_page_addr);
+
+void grub_console_init (void);
+
+void grub_xendisk_fini (void);
+void grub_xendisk_init (void);
+
+#ifdef __x86_64__
+typedef grub_uint64_t grub_xen_mfn_t;
+#else
+typedef grub_uint32_t grub_xen_mfn_t;
+#endif
+typedef unsigned int grub_xen_evtchn_t;
+#endif
+
+#endif
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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_RELOCATOR_XEN_HEADER
+#define GRUB_RELOCATOR_XEN_HEADER 1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/relocator.h>
+
+struct grub_relocator_xen_state
+{
+ grub_addr_t start_info;
+ grub_addr_t paging_start;
+ grub_addr_t paging_size;
+ grub_addr_t mfn_list;
+ grub_addr_t stack;
+ grub_addr_t entry_point;
+};
+
+grub_err_t
+grub_relocator_xen_boot (struct grub_relocator *rel,
+ struct grub_relocator_xen_state state,
+ grub_uint64_t remapper_pfn,
+ grub_addr_t remapper_virt,
+ grub_uint64_t trampoline_pfn,
+ grub_addr_t trampoline_virt);
+
+#endif
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 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_XEN_FILE_HEADER
+#define GRUB_XEN_FILE_HEADER 1
+
+#include <grub/types.h>
+#include <grub/elf.h>
+#include <grub/elfload.h>
+
+grub_elf_t grub_xen_file (grub_file_t file);
+
+struct grub_xen_file_info
+{
+ grub_uint64_t kern_start, kern_end;
+ grub_uint64_t virt_base;
+ grub_uint64_t entry_point;
+ grub_uint64_t hypercall_page;
+ grub_uint64_t paddr_offset;
+ int has_hypercall_page;
+ int has_note;
+ int has_xen_guest;
+ int extended_cr3;
+ enum
+ {
+ GRUB_XEN_FILE_I386 = 1,
+ GRUB_XEN_FILE_I386_PAE = 2,
+ GRUB_XEN_FILE_I386_PAE_BIMODE = 3,
+ GRUB_XEN_FILE_X86_64 = 4
+ } arch;
+};
+
+grub_err_t
+grub_xen_get_info32 (grub_elf_t elf, struct grub_xen_file_info *xi);
+grub_err_t
+grub_xen_get_info64 (grub_elf_t elf, struct grub_xen_file_info *xi);
+grub_err_t grub_xen_get_info (grub_elf_t elf, struct grub_xen_file_info *xi);
+
+#endif
# define ELFCLASSXX ELFCLASS32
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
+# define Elf_Nhdr Elf32_Nhdr
# define Elf_Addr Elf32_Addr
# define Elf_Sym Elf32_Sym
# define Elf_Off Elf32_Off
# define ELF_R_SYM(val) ELF32_R_SYM(val)
# define ELF_R_TYPE(val) ELF32_R_TYPE(val)
# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
+#define XEN_NOTE_SIZE 132
#elif defined(MKIMAGE_ELF64)
# define SUFFIX(x) x ## 64
# define ELFCLASSXX ELFCLASS64
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
+# define Elf_Nhdr Elf64_Nhdr
# define Elf_Addr Elf64_Addr
# define Elf_Sym Elf64_Sym
# define Elf_Off Elf64_Off
# define ELF_R_SYM(val) ELF64_R_SYM(val)
# define ELF_R_TYPE(val) ELF64_R_TYPE(val)
# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val)
+#define XEN_NOTE_SIZE 120
#else
#error "I'm confused"
#endif
static Elf_Addr SUFFIX (entry_point);
+static void
+SUFFIX (generate_elf) (const struct grub_install_image_target_desc *image_target,
+ int note, char **core_img, size_t *core_size,
+ Elf_Addr target_addr, grub_size_t align,
+ size_t kernel_size, size_t bss_size)
+{
+ char *elf_img;
+ size_t program_size;
+ Elf_Ehdr *ehdr;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ int header_size, footer_size = 0;
+ int phnum = 1;
+ int shnum = 4;
+ int string_size = sizeof (".text") + sizeof ("mods") + 1;
+
+ if (image_target->id != IMAGE_LOONGSON_ELF)
+ phnum += 2;
+
+ if (note)
+ {
+ phnum++;
+ footer_size += sizeof (struct grub_ieee1275_note);
+ }
+ if (image_target->id == IMAGE_XEN)
+ {
+ phnum++;
+ shnum++;
+ string_size += sizeof (".xen");
+ footer_size += XEN_NOTE_SIZE;
+ }
+ header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
+ + shnum * sizeof (*shdr) + string_size, align);
+
+ program_size = ALIGN_ADDR (*core_size);
+
+ elf_img = xmalloc (program_size + header_size + footer_size);
+ memset (elf_img, 0, program_size + header_size);
+ memcpy (elf_img + header_size, *core_img, *core_size);
+ ehdr = (void *) elf_img;
+ phdr = (void *) (elf_img + sizeof (*ehdr));
+ shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr));
+ memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_CLASS] = ELFCLASSXX;
+ if (!image_target->bigendian)
+ ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+ else
+ ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+ ehdr->e_type = grub_host_to_target16 (ET_EXEC);
+ ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
+ ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
+
+ ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
+ ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
+ ehdr->e_phnum = grub_host_to_target16 (phnum);
+
+ ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr
+ - (grub_uint8_t *) ehdr);
+ if (image_target->id == IMAGE_LOONGSON_ELF)
+ ehdr->e_shentsize = grub_host_to_target16 (0);
+ else
+ ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr));
+ ehdr->e_shnum = grub_host_to_target16 (shnum);
+ ehdr->e_shstrndx = grub_host_to_target16 (1);
+
+ ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
+
+ phdr->p_type = grub_host_to_target32 (PT_LOAD);
+ phdr->p_offset = grub_host_to_target32 (header_size);
+ phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+
+ ehdr->e_entry = grub_host_to_target32 (target_addr);
+ phdr->p_vaddr = grub_host_to_target32 (target_addr);
+ phdr->p_paddr = grub_host_to_target32 (target_addr);
+ phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
+ if (image_target->id == IMAGE_LOONGSON_ELF)
+ ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER
+ | EF_MIPS_PIC | EF_MIPS_CPIC);
+ else
+ ehdr->e_flags = 0;
+ if (image_target->id == IMAGE_LOONGSON_ELF)
+ {
+ phdr->p_filesz = grub_host_to_target32 (*core_size);
+ phdr->p_memsz = grub_host_to_target32 (*core_size);
+ }
+ else
+ {
+ grub_uint32_t target_addr_mods;
+ phdr->p_filesz = grub_host_to_target32 (kernel_size);
+ phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
+ phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+ phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
+ phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+ phdr->p_align = grub_host_to_target32 (image_target->link_align);
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_LOAD);
+ phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
+ phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+ phdr->p_filesz = phdr->p_memsz
+ = grub_host_to_target32 (*core_size - kernel_size);
+
+ target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
+ + image_target->mod_gap,
+ image_target->mod_align);
+ phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods);
+ phdr->p_paddr = grub_host_to_target_addr (target_addr_mods);
+ phdr->p_align = grub_host_to_target32 (image_target->link_align);
+ }
+
+ if (image_target->id == IMAGE_XEN)
+ {
+ char *note_start = (elf_img + program_size + header_size);
+ Elf_Nhdr *note_ptr;
+ char *ptr = (char *) note_start;
+
+ grub_util_info ("adding XEN NOTE segment");
+
+ /* Guest OS. */
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME));
+ note_ptr->n_type = grub_host_to_target32 (6);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME));
+ ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4);
+
+ /* Loader. */
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic"));
+ note_ptr->n_type = grub_host_to_target32 (8);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memcpy (ptr, "generic", sizeof ("generic"));
+ ptr += ALIGN_UP (sizeof ("generic"), 4);
+
+ /* Version. */
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0"));
+ note_ptr->n_type = grub_host_to_target32 (5);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memcpy (ptr, "xen-3.0", sizeof ("xen-3.0"));
+ ptr += ALIGN_UP (sizeof ("xen-3.0"), 4);
+
+ /* Entry. */
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
+ note_ptr->n_type = grub_host_to_target32 (1);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memset (ptr, 0, image_target->voidp_sizeof);
+ ptr += image_target->voidp_sizeof;
+
+ /* Virt base. */
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof);
+ note_ptr->n_type = grub_host_to_target32 (3);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memset (ptr, 0, image_target->voidp_sizeof);
+ ptr += image_target->voidp_sizeof;
+
+ /* PAE. */
+ if (image_target->elf_target == EM_386)
+ {
+ note_ptr = (Elf_Nhdr *) ptr;
+ note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME));
+ note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal"));
+ note_ptr->n_type = grub_host_to_target32 (9);
+ ptr += sizeof (Elf_Nhdr);
+ memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME));
+ ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4);
+ memcpy (ptr, "yes", sizeof ("yes"));
+ ptr += ALIGN_UP (sizeof ("yes"), 4);
+ }
+
+ assert (XEN_NOTE_SIZE == (ptr - note_start));
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_NOTE);
+ phdr->p_flags = grub_host_to_target32 (PF_R);
+ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE);
+ phdr->p_memsz = 0;
+ phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ }
+
+ if (note)
+ {
+ int note_size = sizeof (struct grub_ieee1275_note);
+ struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *)
+ (elf_img + program_size + header_size);
+
+ grub_util_info ("adding CHRP NOTE segment");
+
+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
+ note_ptr->header.n_descsz = grub_host_to_target32 (note_size);
+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
+ strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME);
+ note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
+ note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
+ note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
+ note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
+ note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
+ note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_NOTE);
+ phdr->p_flags = grub_host_to_target32 (PF_R);
+ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = grub_host_to_target32 (note_size);
+ phdr->p_memsz = 0;
+ phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ }
+
+ {
+ char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
+ + shnum * sizeof (*shdr));
+ char *ptr = str_start + 1;
+
+ shdr++;
+
+ shdr->sh_name = grub_host_to_target32 (0);
+ shdr->sh_type = grub_host_to_target32 (SHT_STRTAB);
+ shdr->sh_addr = grub_host_to_target_addr (0);
+ shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img);
+ shdr->sh_size = grub_host_to_target32 (string_size);
+ shdr->sh_link = grub_host_to_target32 (0);
+ shdr->sh_info = grub_host_to_target32 (0);
+ shdr->sh_addralign = grub_host_to_target32 (align);
+ shdr->sh_entsize = grub_host_to_target32 (0);
+ shdr++;
+
+ memcpy (ptr, ".text", sizeof (".text"));
+
+ shdr->sh_name = grub_host_to_target32 (ptr - str_start);
+ ptr += sizeof (".text");
+ shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+ shdr->sh_addr = grub_host_to_target_addr (target_addr);
+ shdr->sh_offset = grub_host_to_target_addr (header_size);
+ shdr->sh_size = grub_host_to_target32 (kernel_size);
+ shdr->sh_link = grub_host_to_target32 (0);
+ shdr->sh_info = grub_host_to_target32 (0);
+ shdr->sh_addralign = grub_host_to_target32 (align);
+ shdr->sh_entsize = grub_host_to_target32 (0);
+ shdr++;
+
+ memcpy (ptr, "mods", sizeof ("mods"));
+ shdr->sh_name = grub_host_to_target32 (ptr - str_start);
+ ptr += sizeof ("mods");
+ shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+ shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
+ shdr->sh_offset = grub_host_to_target_addr (header_size + kernel_size);
+ shdr->sh_size = grub_host_to_target32 (*core_size - kernel_size);
+ shdr->sh_link = grub_host_to_target32 (0);
+ shdr->sh_info = grub_host_to_target32 (0);
+ shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
+ shdr->sh_entsize = grub_host_to_target32 (0);
+ shdr++;
+
+ if (image_target->id == IMAGE_XEN)
+ {
+ memcpy (ptr, ".xen", sizeof (".xen"));
+ shdr->sh_name = grub_host_to_target32 (ptr - str_start);
+ ptr += sizeof (".xen");
+ shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+ shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
+ shdr->sh_offset = grub_host_to_target_addr (program_size + header_size);
+ shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE);
+ shdr->sh_link = grub_host_to_target32 (0);
+ shdr->sh_info = grub_host_to_target32 (0);
+ shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
+ shdr->sh_entsize = grub_host_to_target32 (0);
+ shdr++;
+ }
+ }
+
+ free (*core_img);
+ *core_img = elf_img;
+ *core_size = program_size + header_size + footer_size;
+}
+
/* Relocate symbols; note that this function overwrites the symbol table.
Return the address of a start symbol. */
static Elf_Addr
#undef ELFCLASSXX
#undef Elf_Ehdr
#undef Elf_Phdr
+#undef Elf_Nhdr
#undef Elf_Shdr
#undef Elf_Addr
#undef Elf_Sym
#undef Elf_Half
#undef Elf_Section
#undef ELF_ST_TYPE
+#undef XEN_NOTE_SIZE
IMAGE_I386_IEEE1275,
IMAGE_LOONGSON_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH,
IMAGE_FULOONG2F_FLASH, IMAGE_I386_PC_PXE, IMAGE_MIPS_ARC,
- IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT
+ IMAGE_QEMU_MIPS_FLASH, IMAGE_UBOOT, IMAGE_XEN
} id;
enum
{
.pe_target = GRUB_PE32_MACHINE_X86_64,
.elf_target = EM_X86_64,
},
+ {
+ .dirname = "i386-xen",
+ .names = { "i386-xen", NULL },
+ .voidp_sizeof = 4,
+ .bigendian = 0,
+ .id = IMAGE_XEN,
+ .flags = PLATFORM_FLAGS_NONE,
+ .total_module_size = TARGET_NO_FIELD,
+ .decompressor_compressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+ .section_align = 1,
+ .vaddr_offset = 0,
+ .link_addr = 0,
+ .elf_target = EM_386,
+ .mod_gap = GRUB_KERNEL_I386_XEN_MOD_GAP,
+ .mod_align = GRUB_KERNEL_I386_XEN_MOD_ALIGN,
+ .link_align = 4
+ },
+ {
+ .dirname = "x86_64-xen",
+ .names = { "x86_64-xen", NULL },
+ .voidp_sizeof = 8,
+ .bigendian = 0,
+ .id = IMAGE_XEN,
+ .flags = PLATFORM_FLAGS_NONE,
+ .total_module_size = TARGET_NO_FIELD,
+ .decompressor_compressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_size = TARGET_NO_FIELD,
+ .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+ .section_align = 1,
+ .vaddr_offset = 0,
+ .link_addr = 0,
+ .elf_target = EM_X86_64,
+ .mod_gap = GRUB_KERNEL_X86_64_XEN_MOD_GAP,
+ .mod_align = GRUB_KERNEL_X86_64_XEN_MOD_ALIGN,
+ .link_align = 8
+ },
{
.dirname = "mipsel-loongson",
.names = { "mipsel-yeeloong-flash", NULL },
/* These structures are defined according to the CHRP binding to IEEE1275,
"Client Program Format" section. */
-struct grub_ieee1275_note_hdr
-{
- grub_uint32_t namesz;
- grub_uint32_t descsz;
- grub_uint32_t type;
- char name[sizeof (GRUB_IEEE1275_NOTE_NAME)];
-};
-
struct grub_ieee1275_note_desc
{
grub_uint32_t real_mode;
struct grub_ieee1275_note
{
- struct grub_ieee1275_note_hdr header;
+ Elf32_Nhdr header;
+ char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)];
struct grub_ieee1275_note_desc descriptor;
};
+#define GRUB_XEN_NOTE_NAME "Xen"
+
#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val))
#include <grub/lib/LzmaEnc.h>
kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size,
total_module_size, &start_address, &rel_section,
&reloc_size, &align, image_target);
+ if (image_target->id == IMAGE_XEN && align < 4096)
+ align = 4096;
if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS)
&& (image_target->total_module_size != TARGET_NO_FIELD))
case IMAGE_EFI:
case IMAGE_MIPS_ARC:
case IMAGE_QEMU_MIPS_FLASH:
+ case IMAGE_XEN:
break;
case IMAGE_SPARC64_AOUT:
case IMAGE_SPARC64_RAW:
break;
case IMAGE_LOONGSON_ELF:
case IMAGE_PPC:
+ case IMAGE_XEN:
case IMAGE_COREBOOT:
case IMAGE_I386_IEEE1275:
{
- char *elf_img;
- size_t program_size;
- Elf32_Ehdr *ehdr;
- Elf32_Phdr *phdr;
- grub_uint32_t target_addr;
- int header_size, footer_size = 0;
- int phnum = 1;
-
- if (image_target->id != IMAGE_LOONGSON_ELF)
- phnum += 2;
-
- if (note)
- {
- phnum++;
- footer_size += sizeof (struct grub_ieee1275_note);
- }
- header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr));
-
- program_size = ALIGN_ADDR (core_size);
-
- elf_img = xmalloc (program_size + header_size + footer_size);
- memset (elf_img, 0, program_size + header_size);
- memcpy (elf_img + header_size, core_img, core_size);
- ehdr = (void *) elf_img;
- phdr = (void *) (elf_img + sizeof (*ehdr));
- memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
- ehdr->e_ident[EI_CLASS] = ELFCLASS32;
- if (!image_target->bigendian)
- ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
- else
- ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
- ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
- ehdr->e_type = grub_host_to_target16 (ET_EXEC);
- ehdr->e_machine = grub_host_to_target16 (image_target->elf_target);
- ehdr->e_version = grub_host_to_target32 (EV_CURRENT);
-
- ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr);
- ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr));
- ehdr->e_phnum = grub_host_to_target16 (phnum);
-
- /* No section headers. */
- ehdr->e_shoff = grub_host_to_target32 (0);
- if (image_target->id == IMAGE_LOONGSON_ELF)
- ehdr->e_shentsize = grub_host_to_target16 (0);
- else
- ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr));
- ehdr->e_shnum = grub_host_to_target16 (0);
- ehdr->e_shstrndx = grub_host_to_target16 (0);
-
- ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr));
-
- phdr->p_type = grub_host_to_target32 (PT_LOAD);
- phdr->p_offset = grub_host_to_target32 (header_size);
- phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
-
+ grub_uint64_t target_addr;
if (image_target->id == IMAGE_LOONGSON_ELF)
{
if (comp == GRUB_COMPRESSION_NONE)
}
else
target_addr = image_target->link_addr;
- ehdr->e_entry = grub_host_to_target32 (target_addr);
- phdr->p_vaddr = grub_host_to_target32 (target_addr);
- phdr->p_paddr = grub_host_to_target32 (target_addr);
- phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
- if (image_target->id == IMAGE_LOONGSON_ELF)
- ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER
- | EF_MIPS_PIC | EF_MIPS_CPIC);
- else
- ehdr->e_flags = 0;
- if (image_target->id == IMAGE_LOONGSON_ELF)
- {
- phdr->p_filesz = grub_host_to_target32 (core_size);
- phdr->p_memsz = grub_host_to_target32 (core_size);
- }
+ if (image_target->voidp_sizeof == 4)
+ generate_elf32 (image_target, note, &core_img, &core_size,
+ target_addr, align, kernel_size, bss_size);
else
- {
- grub_uint32_t target_addr_mods;
- phdr->p_filesz = grub_host_to_target32 (kernel_size);
- phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
-
- phdr++;
- phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
- phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
- phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
- phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
- phdr->p_align = grub_host_to_target32 (image_target->link_align);
-
- phdr++;
- phdr->p_type = grub_host_to_target32 (PT_LOAD);
- phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
- phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
- phdr->p_filesz = phdr->p_memsz
- = grub_host_to_target32 (core_size - kernel_size);
-
- if (image_target->id == IMAGE_COREBOOT)
- target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
- else
- target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
- + image_target->mod_gap,
- image_target->mod_align);
- phdr->p_vaddr = grub_host_to_target32 (target_addr_mods);
- phdr->p_paddr = grub_host_to_target32 (target_addr_mods);
- phdr->p_align = grub_host_to_target32 (image_target->link_align);
- }
-
- if (note)
- {
- int note_size = sizeof (struct grub_ieee1275_note);
- struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *)
- (elf_img + program_size + header_size);
-
- grub_util_info ("adding CHRP NOTE segment");
-
- note_ptr->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME));
- note_ptr->header.descsz = grub_host_to_target32 (note_size);
- note_ptr->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE);
- strcpy (note_ptr->header.name, GRUB_IEEE1275_NOTE_NAME);
- note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff);
- note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000);
- note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff);
- note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff);
- note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff);
- note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000);
-
- phdr++;
- phdr->p_type = grub_host_to_target32 (PT_NOTE);
- phdr->p_flags = grub_host_to_target32 (PF_R);
- phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
- phdr->p_vaddr = 0;
- phdr->p_paddr = 0;
- phdr->p_filesz = grub_host_to_target32 (note_size);
- phdr->p_memsz = 0;
- phdr->p_offset = grub_host_to_target32 (header_size + program_size);
- }
-
- free (core_img);
- core_img = elf_img;
- core_size = program_size + header_size + footer_size;
+ generate_elf64 (image_target, note, &core_img, &core_size,
+ target_addr, align, kernel_size, bss_size);
}
break;
}