]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add new ports: i386-xen and x86_64-xen. This allows running GRUB in
authorVladimir Serbinenko <phcoder@gmail.com>
Sat, 9 Nov 2013 20:29:11 +0000 (21:29 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Sat, 9 Nov 2013 20:29:11 +0000 (21:29 +0100)
XEN PV environment and load kernels.

59 files changed:
ChangeLog
conf/Makefile.common
configure.ac
docs/grub.texi
gentpl.py
grub-core/Makefile.am
grub-core/Makefile.core.def
grub-core/commands/boot.c
grub-core/commands/nativedisk.c
grub-core/commands/xen/lsxen.c [new file with mode: 0644]
grub-core/disk/xen/xendisk.c [new file with mode: 0644]
grub-core/fs/cbfs.c
grub-core/io/offset.c [new file with mode: 0644]
grub-core/kern/emu/main.c
grub-core/kern/i386/coreboot/init.c
grub-core/kern/i386/efi/init.c
grub-core/kern/i386/pc/init.c
grub-core/kern/i386/qemu/init.c
grub-core/kern/i386/tsc.c
grub-core/kern/i386/xen/hypercall.S [new file with mode: 0644]
grub-core/kern/i386/xen/startup.S [new file with mode: 0644]
grub-core/kern/ia64/efi/init.c
grub-core/kern/ieee1275/init.c
grub-core/kern/mips/arc/init.c
grub-core/kern/mips/loongson/init.c
grub-core/kern/mips/qemu_mips/init.c
grub-core/kern/x86_64/xen/hypercall.S [new file with mode: 0644]
grub-core/kern/x86_64/xen/startup.S [new file with mode: 0644]
grub-core/kern/xen/init.c [new file with mode: 0644]
grub-core/lib/i386/reboot.c
grub-core/lib/i386/relocator.c
grub-core/lib/i386/relocator_common_c.c [new file with mode: 0644]
grub-core/lib/i386/xen/relocator.S [new file with mode: 0644]
grub-core/lib/legacy_parse.c
grub-core/lib/relocator.c
grub-core/lib/x86_64/xen/relocator.S [new file with mode: 0644]
grub-core/lib/xen/datetime.c [new file with mode: 0644]
grub-core/lib/xen/halt.c [new file with mode: 0644]
grub-core/lib/xen/reboot.c [new file with mode: 0644]
grub-core/lib/xen/relocator.c [new file with mode: 0644]
grub-core/loader/i386/xen.c [new file with mode: 0644]
grub-core/loader/i386/xen_file.c [new file with mode: 0644]
grub-core/loader/i386/xen_file32.c [new file with mode: 0644]
grub-core/loader/i386/xen_file64.c [new file with mode: 0644]
grub-core/loader/i386/xen_fileXX.c [new file with mode: 0644]
grub-core/term/xen/console.c [new file with mode: 0644]
include/grub/disk.h
include/grub/elf.h
include/grub/file.h
include/grub/i386/xen/hypercall.h [new file with mode: 0644]
include/grub/i386/xen/memory.h [new file with mode: 0644]
include/grub/kernel.h
include/grub/offsets.h
include/grub/x86_64/xen/hypercall.h [new file with mode: 0644]
include/grub/xen.h [new file with mode: 0644]
include/grub/xen/relocator.h [new file with mode: 0644]
include/grub/xen_file.h [new file with mode: 0644]
util/grub-mkimagexx.c
util/mkimage.c

index 700161efec94b83401e255e33a3e3ad532588ac5..0f4df906725c9f81e04430508836cb4f054f5b5a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+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.
index 921e576827fb74889c24544c531c37cac1acdb17..0dc26db55fa46eafe8dd8cf25bce6fd05b127a27 100644 (file)
@@ -23,6 +23,9 @@ if COND_arm
   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)/,,$<)\"
index ea38f090f8b406e843b1e3f3ee3d6f0512d634df..3232a8089f585c29d771485f15b64523c12df917 100644 (file)
@@ -133,6 +133,7 @@ fi
 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
@@ -141,6 +142,8 @@ esac
 case "$target_cpu"-"$platform" in
   i386-efi) ;;
   x86_64-efi) ;;
+  i386-xen) ;;
+  x86_64-xen) ;;
   i386-pc) ;;
   i386-multiboot) ;;
   i386-coreboot) ;;
@@ -193,6 +196,7 @@ case "$platform" in
   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" ;;
@@ -1380,6 +1384,8 @@ AM_CONDITIONAL([COND_i386_ieee1275], [test x$target_cpu = xi386 -a x$platform =
 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])
index d1cf73d2eb75fe39f907d39c717ae1c191badd14..ead8fbd55a64f2c602791a2dca44ea1c61b08985 100644 (file)
@@ -2652,6 +2652,7 @@ Heavily limited platforms:
 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
@@ -2707,9 +2708,9 @@ by a digit, like @samp{fd0}, or @samp{cd}.
 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.
index 05f3f969bef3d1d6f9e77b1bd9e72f135764fdba..5f0bba522117255e362c3c21e61b9b364e123069 100644 (file)
--- a/gentpl.py
+++ b/gentpl.py
@@ -21,6 +21,7 @@
 
 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" ]
@@ -42,6 +43,7 @@ GROUPS["arm"]      = [ "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")
@@ -49,7 +51,7 @@ 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"]
 
@@ -59,7 +61,7 @@ GROUPS["videomodules"]   = GRUB_PLATFORMS[:];
 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)
 
index ea11716e6a154bad5aa06961e44e5b8295f323e3..980acf34607a7fcb29dcebead39fc281f8cf93a2 100644 (file)
@@ -130,6 +130,24 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
 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
index a053f203ec44dd740fbadcb181876e4a5c2a5020..20951aab7eae5c1e1cc71a9c59ce664d702ab8e5 100644 (file)
@@ -59,6 +59,11 @@ kernel = {
   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';
 
@@ -90,6 +95,8 @@ kernel = {
   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;
@@ -146,6 +153,7 @@ kernel = {
   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;
@@ -164,11 +172,20 @@ kernel = {
   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;
@@ -578,6 +595,14 @@ module = {
   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;
@@ -745,8 +770,10 @@ module = {
 
 module = {
   name = cpuid;
-  x86 = commands/i386/cpuid.c;
+  common = commands/i386/cpuid.c;
   enable = x86;
+  enable = i386_xen;
+  enable = x86_64_xen;
 };
 
 module = {
@@ -803,6 +830,8 @@ 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;
@@ -821,6 +850,8 @@ module = {
   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;
 };
@@ -1444,6 +1475,11 @@ module = {
   common = io/gzio.c;
 };
 
+module = {
+  name = offsetio;
+  common = io/offset.c;
+};
+
 module = {
   name = bufio;
   common = io/bufio.c;
@@ -1477,13 +1513,21 @@ module = {
   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;
@@ -1491,6 +1535,7 @@ module = {
   enable = mips;
   enable = powerpc;
   enable = x86;
+  enable = xen;
 };
 
 module = {
@@ -1502,6 +1547,8 @@ 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;
@@ -1594,6 +1641,12 @@ module = {
 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;
@@ -2015,11 +2068,13 @@ module = {
   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 = {
@@ -2053,8 +2108,12 @@ 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 = {
index e0148c7f61c0de7d20df5e8425745bfb1e7d644d..bbca81e947641f00e7cdb019ef771e19389aeef4 100644 (file)
@@ -146,8 +146,7 @@ grub_loader_boot (void)
     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)
     {
index 714aa11bd4d54e057ea8df30b4993488ef32e2e8..33b6b99eaaf4b204179e1b8114c3f5237cf27fa9 100644 (file)
@@ -75,6 +75,7 @@ get_uuid (const char *name, char **uuid, int getnative)
       /* Native disks.  */
     case GRUB_DISK_DEVICE_ATA_ID:
     case GRUB_DISK_DEVICE_SCSI_ID:
+    case GRUB_DISK_DEVICE_XEN:
       if (getnative)
        break;
 
diff --git a/grub-core/commands/xen/lsxen.c b/grub-core/commands/xen/lsxen.c
new file mode 100644 (file)
index 0000000..8415495
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  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);
+}
diff --git a/grub-core/disk/xen/xendisk.c b/grub-core/disk/xen/xendisk.c
new file mode 100644 (file)
index 0000000..c449848
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ *  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);
+    }
+}
index 0530c9b8a7392b10c7ef278b1dfeb569e51e2719..93a38003e0ff8dd40403645ba8820ea94c9ea169 100644 (file)
@@ -267,7 +267,8 @@ grub_cbfs_close (grub_file_t file)
   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;
@@ -375,7 +376,7 @@ static struct grub_fs grub_cbfs_fs = {
 
 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);
@@ -384,7 +385,7 @@ GRUB_MOD_INIT (cbfs)
 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
 }
diff --git a/grub-core/io/offset.c b/grub-core/io/offset.c
new file mode 100644 (file)
index 0000000..ebed0eb
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  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;
+}
index 87ae256f95c5549e7e85948056aa5710cfb1ff34..8696e84b91aedb2f2192ac90b44013768a2795d5 100644 (file)
@@ -41,6 +41,7 @@
 #include <grub/env.h>
 #include <grub/partition.h>
 #include <grub/i18n.h>
+#include <grub/loader.h>
 #include <grub/util/misc.h>
 
 #include "progname.h"
@@ -75,9 +76,10 @@ grub_machine_get_bootlocation (char **device, char **path)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
 {
-  grub_console_fini ();
+  if (flags & GRUB_LOADER_FLAG_NORETURN)
+    grub_console_fini ();
 }
 
 \f
index 777d7489c2f673c8be53c9b366ef1261cf06598d..6b150b47d886732a3429a66fce84d955bb65a2f8 100644 (file)
@@ -130,8 +130,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
 }
 
 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 ();
 }
index 6bd8f3e87854dac53f3d8e007b9b9befe40492e6..7616e629d7b81255142722dbdf99732636af62bf 100644 (file)
@@ -35,7 +35,8 @@ grub_machine_init (void)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
 {
-  grub_efi_fini ();
+  if (flags & GRUB_LOADER_FLAG_NORETURN)
+    grub_efi_fini ();
 }
index 5b685040a7861eb548fe47dc6516117b08c45567..2319adf12794ad55074a224e3addc41b2aff6eb8 100644 (file)
@@ -239,8 +239,9 @@ grub_machine_init (void)
 }
 
 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 ();
 }
index cad6c40a2b145128873214d04baaeeb214fee5da..e05ccee965633b539dd91c9a8121b7b9ca37ea3e 100644 (file)
@@ -277,8 +277,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
 }
 
 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 ();
 }
index 608136b3d86197c5a0cfaba89fd6e714fae1935f..3a4cae601d039b2b9c25de69fa3e59cccdd170b6 100644 (file)
 #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). */
@@ -65,6 +69,8 @@ grub_cpu_is_tsc_supported (void)
   return (d & (1 << 4)) != 0;
 }
 
+#ifndef GRUB_MACHINE_XEN
+
 static void
 grub_pit_wait (grub_uint16_t tics)
 {
@@ -92,6 +98,7 @@ 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)
@@ -103,6 +110,7 @@ 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)
@@ -116,10 +124,22 @@ 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 ();
@@ -133,4 +153,5 @@ grub_tsc_init (void)
       grub_fatal ("no TSC found");
 #endif
     }
+#endif
 }
diff --git a/grub-core/kern/i386/xen/hypercall.S b/grub-core/kern/i386/xen/hypercall.S
new file mode 100644 (file)
index 0000000..aa47cac
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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
diff --git a/grub-core/kern/i386/xen/startup.S b/grub-core/kern/i386/xen/startup.S
new file mode 100644 (file)
index 0000000..fbe8300
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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):      
index 7fa6fbf7125b41b9f941dc6673ce992c6df03bfe..c514b0a1f9e06c2a089a2155b1c3f13ec37433ee 100644 (file)
@@ -68,9 +68,10 @@ grub_machine_init (void)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags)
 {
-  grub_efi_fini ();
+  if (flags & GRUB_LOADER_FLAG_NORETURN)
+    grub_efi_fini ();
 }
 
 void
index ce8eadbd3ae31059937d8b7971372a18fbb7bb4e..acf73703c3fadfd47a2fadab8b476451c2c45004 100644 (file)
@@ -298,10 +298,13 @@ grub_machine_init (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
index ddee814c5d71c1e50331e045bb6c3819c7298869..f12026e95eed93780685d0317230496fe45c8566 100644 (file)
@@ -259,7 +259,7 @@ grub_machine_init (void)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
 {
 }
 
index 3ed1ded61b2144a907a95fa1bf3babd30f72b4cb..d2f5795884acc3ac5a2e77ac2eb8c7d529315274 100644 (file)
@@ -217,7 +217,7 @@ grub_machine_init (void)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
 {
 }
 
index 6a5af2a93fb0d0ba57deb05aef1ab8d2bfa2bb14..2ea2eb4fde5ce8fb07fff66712f893126b960b31 100644 (file)
@@ -70,7 +70,7 @@ grub_machine_init (void)
 }
 
 void
-grub_machine_fini (void)
+grub_machine_fini (int flags __attribute__ ((unused)))
 {
 }
 
diff --git a/grub-core/kern/x86_64/xen/hypercall.S b/grub-core/kern/x86_64/xen/hypercall.S
new file mode 100644 (file)
index 0000000..9b04db6
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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
diff --git a/grub-core/kern/x86_64/xen/startup.S b/grub-core/kern/x86_64/xen/startup.S
new file mode 100644 (file)
index 0000000..7217ee5
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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):      
diff --git a/grub-core/kern/xen/init.c b/grub-core/kern/xen/init.c
new file mode 100644 (file)
index 0000000..3bfd99f
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ *  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;
+}
index 0587f1477984bac4f96e87500e52a1a70b4507b4..a234244dce5b4c5afd5c68e579c4519a870cda36 100644 (file)
@@ -58,4 +58,3 @@ grub_reboot (void)
 
   while (1);
 }
-
index 0170eed390713fa156eca2133ef233c3ca658ce4..d2a1b27ae0e2fc952e57f70da12b0c7a1b4af68d 100644 (file)
 #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;
@@ -85,75 +72,6 @@ extern struct grub_i386_idt grub_relocator16_idt;
 
 #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,
diff --git a/grub-core/lib/i386/relocator_common_c.c b/grub-core/lib/i386/relocator_common_c.c
new file mode 100644 (file)
index 0000000..7be609b
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ *  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));
+}
diff --git a/grub-core/lib/i386/xen/relocator.S b/grub-core/lib/i386/xen/relocator.S
new file mode 100644 (file)
index 0000000..a1677db
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ *  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)
index 4dc887ad27009129f47cb58f84920bdf97589a80..300d8b96110d3f40df144d34c723642d0d444f5b 100644 (file)
@@ -250,6 +250,9 @@ static struct legacy_command legacy_commands[] =
     {"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",
index b86a6c0dc3b7c44ae585d583a9a90d066a51b043..c86c5e886b220480bf724b715753ba3571aa9cd0 100644 (file)
@@ -1432,7 +1432,7 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel,
 #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
diff --git a/grub-core/lib/x86_64/xen/relocator.S b/grub-core/lib/x86_64/xen/relocator.S
new file mode 100644 (file)
index 0000000..28ad4c7
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *  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)
diff --git a/grub-core/lib/xen/datetime.c b/grub-core/lib/xen/datetime.c
new file mode 100644 (file)
index 0000000..d96176e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  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");
+}
diff --git a/grub-core/lib/xen/halt.c b/grub-core/lib/xen/halt.c
new file mode 100644 (file)
index 0000000..2aceead
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  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 (;;);
+}
diff --git a/grub-core/lib/xen/reboot.c b/grub-core/lib/xen/reboot.c
new file mode 100644 (file)
index 0000000..fd7609a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  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 (;;);
+}
diff --git a/grub-core/lib/xen/relocator.c b/grub-core/lib/xen/relocator.c
new file mode 100644 (file)
index 0000000..8f427d3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  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;
+}
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
new file mode 100644 (file)
index 0000000..91b66f8
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ *  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);
+}
diff --git a/grub-core/loader/i386/xen_file.c b/grub-core/loader/i386/xen_file.c
new file mode 100644 (file)
index 0000000..fb7f692
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  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");
+}
diff --git a/grub-core/loader/i386/xen_file32.c b/grub-core/loader/i386/xen_file32.c
new file mode 100644 (file)
index 0000000..340d445
--- /dev/null
@@ -0,0 +1,7 @@
+#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"
diff --git a/grub-core/loader/i386/xen_file64.c b/grub-core/loader/i386/xen_file64.c
new file mode 100644 (file)
index 0000000..c410493
--- /dev/null
@@ -0,0 +1,7 @@
+#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"
diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
new file mode 100644 (file)
index 0000000..ea0656c
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *  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");
+}
diff --git a/grub-core/term/xen/console.c b/grub-core/term/xen/console.c
new file mode 100644 (file)
index 0000000..a1f15f7
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  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");
+}
index 3e61c96423dfcec524b417e81e441d277d51667f..b385af826fc44ed8b1aa63f8b7d1ad4f1834fbc9 100644 (file)
@@ -48,6 +48,7 @@ enum grub_disk_dev_id
     GRUB_DISK_DEVICE_PROCFS_ID,
     GRUB_DISK_DEVICE_CBFSDISK_ID,
     GRUB_DISK_DEVICE_UBOOTDISK_ID,
+    GRUB_DISK_DEVICE_XEN,
   };
 
 struct grub_disk;
index 708cd6a95d07b2d2191d77c31b90fbd8fa3eba7c..f64d6a8919b8e46e3e8b0233bf219eb4a45b7b23 100644 (file)
@@ -2454,7 +2454,9 @@ typedef Elf32_Addr Elf32_Conflict;
 #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;
@@ -2477,7 +2479,9 @@ typedef Elf32_Xword Elf_Xword;
 #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;
index f8ae8d9a891635a90565ebb3f08b69334a3d51a4..739488cbe59aaa044b37611d00fb2c6c615e2c31 100644 (file)
@@ -158,4 +158,10 @@ grub_file_seekable (const grub_file_t file)
   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 */
diff --git a/include/grub/i386/xen/hypercall.h b/include/grub/i386/xen/hypercall.h
new file mode 100644 (file)
index 0000000..0152b2b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  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
diff --git a/include/grub/i386/xen/memory.h b/include/grub/i386/xen/memory.h
new file mode 100644 (file)
index 0000000..e69de29
index 52105fcce481af9de76771afa1a250b0dcd80f22..a5067ef79b8e91345e51957603f7b07a9f5b3717 100644 (file)
@@ -78,7 +78,7 @@ struct grub_module_info64
 #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
@@ -114,7 +114,7 @@ void grub_main (void) __attribute__ ((noreturn));
 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
index 08e490c9631016d1c786a25a5cf5286165ae5efa..0a7b89a6deab64bb5326de0c308f7ca8d78cfee0 100644 (file)
 #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
diff --git a/include/grub/x86_64/xen/hypercall.h b/include/grub/x86_64/xen/hypercall.h
new file mode 100644 (file)
index 0000000..780db4d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  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
diff --git a/include/grub/xen.h b/include/grub/xen.h
new file mode 100644 (file)
index 0000000..062c95d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  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
diff --git a/include/grub/xen/relocator.h b/include/grub/xen/relocator.h
new file mode 100644 (file)
index 0000000..ae45dce
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  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
diff --git a/include/grub/xen_file.h b/include/grub/xen_file.h
new file mode 100644 (file)
index 0000000..4b2ccba
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  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
index fea553c14871db9ac1769dcdd1c7583e293480a6..acfa71f1d1be691cd9fccc94be09b6e5d0d3eb2c 100644 (file)
@@ -25,6 +25,7 @@
 # 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
@@ -1095,6 +1401,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 #undef ELFCLASSXX
 #undef Elf_Ehdr
 #undef Elf_Phdr
+#undef Elf_Nhdr
 #undef Elf_Shdr
 #undef Elf_Addr
 #undef Elf_Sym
@@ -1107,3 +1414,4 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
 #undef Elf_Half
 #undef Elf_Section
 #undef ELF_ST_TYPE
+#undef XEN_NOTE_SIZE
index 1d2c7eac13283c754500480a3ad4b1dc1c5446cb..c71f1fdcc6862424a45e19931c35dceb43828035 100644 (file)
@@ -66,7 +66,7 @@ struct grub_install_image_target_desc
     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
     {
@@ -240,6 +240,44 @@ static const struct grub_install_image_target_desc image_targets[] =
       .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 },
@@ -618,14 +656,6 @@ grub_target_to_host_real (const struct grub_install_image_target_desc *image_tar
 /* 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;
@@ -638,10 +668,13 @@ struct grub_ieee1275_note_desc
 
 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>
@@ -903,6 +936,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
     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))
@@ -1135,6 +1170,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
     case IMAGE_EFI:
     case IMAGE_MIPS_ARC:
     case IMAGE_QEMU_MIPS_FLASH:
+    case IMAGE_XEN:
       break;
     case IMAGE_SPARC64_AOUT:
     case IMAGE_SPARC64_RAW:
@@ -1700,65 +1736,11 @@ grub_install_generate_image (const char *dir, const char *prefix,
       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)
@@ -1769,84 +1751,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
          }
        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;
     }