Add new ports: i386-xen and x86_64-xen. This allows running GRUB in
XEN PV environment and load kernels.
This commit is contained in:
parent
1a46a3a4b3
commit
9612ebc00e
59 changed files with 4167 additions and 259 deletions
|
@ -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.
|
||||
|
|
|
@ -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)/,,$<)\"
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
90
grub-core/commands/xen/lsxen.c
Normal file
90
grub-core/commands/xen/lsxen.c
Normal file
|
@ -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);
|
||||
}
|
453
grub-core/disk/xen/xendisk.c
Normal file
453
grub-core/disk/xen/xendisk.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
111
grub-core/io/offset.c
Normal file
111
grub-core/io/offset.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -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,8 +76,9 @@ grub_machine_get_bootlocation (char **device, char **path)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_console_fini ();
|
||||
}
|
||||
|
||||
|
|
|
@ -130,8 +130,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_vga_text_fini ();
|
||||
grub_stop_floppy ();
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_efi_fini ();
|
||||
}
|
||||
|
|
|
@ -239,8 +239,9 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_console_fini ();
|
||||
grub_stop_floppy ();
|
||||
}
|
||||
|
|
|
@ -277,8 +277,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_vga_text_fini ();
|
||||
grub_stop_floppy ();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,11 @@
|
|||
#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
|
||||
}
|
||||
|
|
43
grub-core/kern/i386/xen/hypercall.S
Normal file
43
grub-core/kern/i386/xen/hypercall.S
Normal file
|
@ -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
|
38
grub-core/kern/i386/xen/startup.S
Normal file
38
grub-core/kern/i386/xen/startup.S
Normal file
|
@ -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):
|
|
@ -68,8 +68,9 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
grub_efi_fini ();
|
||||
}
|
||||
|
||||
|
|
|
@ -298,11 +298,14 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags)
|
||||
{
|
||||
if (flags & GRUB_LOADER_FLAG_NORETURN)
|
||||
{
|
||||
grub_ofdisk_fini ();
|
||||
grub_console_fini ();
|
||||
}
|
||||
}
|
||||
|
||||
grub_uint64_t
|
||||
grub_rtc_get_time_ms (void)
|
||||
|
|
|
@ -259,7 +259,7 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ grub_machine_init (void)
|
|||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
grub_machine_fini (int flags __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
53
grub-core/kern/x86_64/xen/hypercall.S
Normal file
53
grub-core/kern/x86_64/xen/hypercall.S
Normal file
|
@ -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
|
38
grub-core/kern/x86_64/xen/startup.S
Normal file
38
grub-core/kern/x86_64/xen/startup.S
Normal file
|
@ -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):
|
571
grub-core/kern/xen/init.c
Normal file
571
grub-core/kern/xen/init.c
Normal file
|
@ -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;
|
||||
}
|
|
@ -58,4 +58,3 @@ grub_reboot (void)
|
|||
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,19 +28,6 @@
|
|||
#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,
|
||||
|
|
109
grub-core/lib/i386/relocator_common_c.c
Normal file
109
grub-core/lib/i386/relocator_common_c.c
Normal file
|
@ -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));
|
||||
}
|
146
grub-core/lib/i386/xen/relocator.S
Normal file
146
grub-core/lib/i386/xen/relocator.S
Normal file
|
@ -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)
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
154
grub-core/lib/x86_64/xen/relocator.S
Normal file
154
grub-core/lib/x86_64/xen/relocator.S
Normal file
|
@ -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)
|
40
grub-core/lib/xen/datetime.c
Normal file
40
grub-core/lib/xen/datetime.c
Normal file
|
@ -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");
|
||||
}
|
32
grub-core/lib/xen/halt.c
Normal file
32
grub-core/lib/xen/halt.c
Normal file
|
@ -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 (;;);
|
||||
}
|
32
grub-core/lib/xen/reboot.c
Normal file
32
grub-core/lib/xen/reboot.c
Normal file
|
@ -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 (;;);
|
||||
}
|
125
grub-core/lib/xen/relocator.c
Normal file
125
grub-core/lib/xen/relocator.c
Normal file
|
@ -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;
|
||||
}
|
712
grub-core/loader/i386/xen.c
Normal file
712
grub-core/loader/i386/xen.c
Normal file
|
@ -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);
|
||||
}
|
91
grub-core/loader/i386/xen_file.c
Normal file
91
grub-core/loader/i386/xen_file.c
Normal file
|
@ -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");
|
||||
}
|
7
grub-core/loader/i386/xen_file32.c
Normal file
7
grub-core/loader/i386/xen_file32.c
Normal file
|
@ -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"
|
7
grub-core/loader/i386/xen_file64.c
Normal file
7
grub-core/loader/i386/xen_file64.c
Normal file
|
@ -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"
|
344
grub-core/loader/i386/xen_fileXX.c
Normal file
344
grub-core/loader/i386/xen_fileXX.c
Normal file
|
@ -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");
|
||||
}
|
122
grub-core/term/xen/console.c
Normal file
122
grub-core/term/xen/console.c
Normal file
|
@ -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");
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
85
include/grub/i386/xen/hypercall.h
Normal file
85
include/grub/i386/xen/hypercall.h
Normal file
|
@ -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
|
0
include/grub/i386/xen/memory.h
Normal file
0
include/grub/i386/xen/memory.h
Normal 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
|
||||
|
|
|
@ -99,7 +99,12 @@
|
|||
#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
|
||||
|
|
34
include/grub/x86_64/xen/hypercall.h
Normal file
34
include/grub/x86_64/xen/hypercall.h
Normal file
|
@ -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
|
93
include/grub/xen.h
Normal file
93
include/grub/xen.h
Normal file
|
@ -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
|
44
include/grub/xen/relocator.h
Normal file
44
include/grub/xen/relocator.h
Normal file
|
@ -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
|
54
include/grub/xen_file.h
Normal file
54
include/grub/xen_file.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
@ -37,11 +38,13 @@
|
|||
# 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
|
||||
|
@ -54,12 +57,315 @@
|
|||
# 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
|
||||
|
|
196
util/mkimage.c
196
util/mkimage.c
|
@ -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);
|
||||
if (image_target->voidp_sizeof == 4)
|
||||
generate_elf32 (image_target, note, &core_img, &core_size,
|
||||
target_addr, align, kernel_size, bss_size);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue