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:
Vladimir Serbinenko 2013-11-09 21:29:11 +01:00
parent 1a46a3a4b3
commit 9612ebc00e
59 changed files with 4167 additions and 259 deletions

View file

@ -130,6 +130,24 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
endif
if COND_i386_xen
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/xen/hypercall.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h
endif
if COND_x86_64_xen
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/x86_64/xen/hypercall.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h
endif
if COND_x86_64_efi
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h

View file

@ -59,6 +59,11 @@ kernel = {
ia64_efi_ldflags = '-Wl,-r,-d';
ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
x86_64_xen_ldflags = '-Wl,-Ttext=0';
x86_64_xen_cppflags = '$(CPPFLAGS_XEN)';
i386_xen_ldflags = '-Wl,-Ttext=0';
i386_xen_cppflags = '$(CPPFLAGS_XEN)';
arm_efi_ldflags = '-Wl,-r,-d';
arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
@ -90,6 +95,8 @@ kernel = {
i386_pc_startup = kern/i386/pc/startup.S;
i386_efi_startup = kern/i386/efi/startup.S;
x86_64_efi_startup = kern/x86_64/efi/startup.S;
i386_xen_startup = kern/i386/xen/startup.S;
x86_64_xen_startup = kern/x86_64/xen/startup.S;
i386_qemu_startup = kern/i386/qemu/startup.S;
i386_ieee1275_startup = kern/i386/ieee1275/startup.S;
i386_coreboot_startup = kern/i386/coreboot/startup.S;
@ -146,6 +153,7 @@ kernel = {
terminfoinkernel = lib/arg.c;
i386 = kern/i386/dl.c;
i386_xen = kern/i386/dl.c;
i386_coreboot = kern/i386/coreboot/init.c;
i386_multiboot = kern/i386/coreboot/init.c;
@ -164,11 +172,20 @@ kernel = {
i386_efi = kern/i386/efi/init.c;
i386_efi = bus/pci.c;
x86_64_efi = kern/x86_64/dl.c;
x86_64 = kern/x86_64/dl.c;
x86_64_xen = kern/x86_64/dl.c;
x86_64_efi = kern/x86_64/efi/callwrap.S;
x86_64_efi = kern/i386/efi/init.c;
x86_64_efi = bus/pci.c;
xen = kern/i386/tsc.c;
x86_64_xen = kern/x86_64/xen/hypercall.S;
i386_xen = kern/i386/xen/hypercall.S;
xen = kern/xen/init.c;
xen = term/xen/console.c;
xen = disk/xen/xendisk.c;
xen = commands/boot.c;
ia64_efi = kern/ia64/efi/startup.S;
ia64_efi = kern/ia64/efi/init.c;
ia64_efi = kern/ia64/dl.c;
@ -578,6 +595,14 @@ module = {
enable = mips_arc;
};
module = {
name = lsxen;
common = commands/xen/lsxen.c;
cppflags = '$(CPPFLAGS_XEN)';
enable = xen;
};
module = {
name = check_nt_hiberfil;
common = commands/i386/nthibr.c;
@ -745,8 +770,10 @@ module = {
module = {
name = cpuid;
x86 = commands/i386/cpuid.c;
common = commands/i386/cpuid.c;
enable = x86;
enable = i386_xen;
enable = x86_64_xen;
};
module = {
@ -803,6 +830,8 @@ module = {
i386_multiboot = lib/i386/halt.c;
i386_coreboot = lib/i386/halt.c;
i386_qemu = lib/i386/halt.c;
xen = lib/xen/halt.c;
xen_cppflags = '$(CPPFLAGS_XEN)';
efi = lib/efi/halt.c;
ieee1275 = lib/ieee1275/halt.c;
emu = lib/emu/halt.c;
@ -821,6 +850,8 @@ module = {
mips_arc = lib/mips/arc/reboot.c;
mips_loongson = lib/mips/loongson/reboot.c;
mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
xen = lib/xen/reboot.c;
xen_cppflags = '$(CPPFLAGS_XEN)';
uboot = lib/uboot/reboot.c;
common = commands/reboot.c;
};
@ -1444,6 +1475,11 @@ module = {
common = io/gzio.c;
};
module = {
name = offsetio;
common = io/offset.c;
};
module = {
name = bufio;
common = io/bufio.c;
@ -1477,13 +1513,21 @@ module = {
x86 = lib/i386/relocator64.S;
i386 = lib/i386/relocator_asm.S;
x86_64 = lib/x86_64/relocator_asm.S;
i386_xen = lib/i386/relocator_asm.S;
x86_64_xen = lib/x86_64/relocator_asm.S;
x86 = lib/i386/relocator.c;
x86 = lib/i386/relocator_common_c.c;
ieee1275 = lib/ieee1275/relocator.c;
efi = lib/efi/relocator.c;
mips = lib/mips/relocator_asm.S;
mips = lib/mips/relocator.c;
powerpc = lib/powerpc/relocator_asm.S;
powerpc = lib/powerpc/relocator.c;
xen = lib/xen/relocator.c;
i386_xen = lib/i386/xen/relocator.S;
x86_64_xen = lib/x86_64/xen/relocator.S;
xen = lib/i386/relocator_common_c.c;
xen_cppflags = '$(CPPFLAGS_XEN)';
extra_dist = lib/i386/relocator_common.S;
extra_dist = kern/powerpc/cache_flush.S;
@ -1491,6 +1535,7 @@ module = {
enable = mips;
enable = powerpc;
enable = x86;
enable = xen;
};
module = {
@ -1502,6 +1547,8 @@ module = {
powerpc_ieee1275 = lib/ieee1275/datetime.c;
sparc64_ieee1275 = lib/ieee1275/cmos.c;
powerpc_ieee1275 = lib/ieee1275/cmos.c;
xen = lib/xen/datetime.c;
xen_cppflags = '$(CPPFLAGS_XEN)';
mips_arc = lib/arc/datetime.c;
enable = noemu;
@ -1594,6 +1641,12 @@ module = {
module = {
name = linux;
x86 = loader/i386/linux.c;
xen = loader/i386/xen.c;
xen = loader/i386/xen_file.c;
xen = loader/i386/xen_file32.c;
xen = loader/i386/xen_file64.c;
extra_dist = loader/i386/xen_fileXX.c;
xen_cppflags = '$(CPPFLAGS_XEN)';
i386_pc = lib/i386/pc/vesa_modes_table.c;
mips = loader/mips/linux.c;
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
@ -2015,11 +2068,13 @@ module = {
emu = lib/i386/pc/vesa_modes_table.c;
i386_efi = lib/i386/pc/vesa_modes_table.c;
x86_64_efi = lib/i386/pc/vesa_modes_table.c;
xen = lib/i386/pc/vesa_modes_table.c;
enable = i386_pc;
enable = i386_efi;
enable = x86_64_efi;
enable = emu;
enable = xen;
};
module = {
@ -2053,8 +2108,12 @@ module = {
module = {
name = backtrace;
x86 = lib/i386/backtrace.c;
i386_xen = lib/i386/backtrace.c;
x86_64_xen = lib/i386/backtrace.c;
common = lib/backtrace.c;
enable = x86;
enable = i386_xen;
enable = x86_64_xen;
};
module = {

View file

@ -146,8 +146,7 @@ grub_loader_boot (void)
return grub_error (GRUB_ERR_NO_KERNEL,
N_("you need to load the kernel first"));
if (grub_loader_flags & GRUB_LOADER_FLAG_NORETURN)
grub_machine_fini ();
grub_machine_fini (grub_loader_flags);
for (cur = preboots_head; cur; cur = cur->next)
{

View file

@ -75,6 +75,7 @@ get_uuid (const char *name, char **uuid, int getnative)
/* Native disks. */
case GRUB_DISK_DEVICE_ATA_ID:
case GRUB_DISK_DEVICE_SCSI_ID:
case GRUB_DISK_DEVICE_XEN:
if (getnative)
break;

View 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);
}

View 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);
}
}

View file

@ -267,7 +267,8 @@ grub_cbfs_close (grub_file_t file)
return grub_errno;
}
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) \
&& !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
static char *cbfsdisk_addr;
static grub_off_t cbfsdisk_size = 0;
@ -375,7 +376,7 @@ static struct grub_fs grub_cbfs_fs = {
GRUB_MOD_INIT (cbfs)
{
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
init_cbfsdisk ();
#endif
grub_fs_register (&grub_cbfs_fs);
@ -384,7 +385,7 @@ GRUB_MOD_INIT (cbfs)
GRUB_MOD_FINI (cbfs)
{
grub_fs_unregister (&grub_cbfs_fs);
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
fini_cbfsdisk ();
#endif
}

111
grub-core/io/offset.c Normal file
View 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;
}

View file

@ -41,6 +41,7 @@
#include <grub/env.h>
#include <grub/partition.h>
#include <grub/i18n.h>
#include <grub/loader.h>
#include <grub/util/misc.h>
#include "progname.h"
@ -75,9 +76,10 @@ grub_machine_get_bootlocation (char **device, char **path)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_console_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_console_fini ();
}

View file

@ -130,8 +130,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_vga_text_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_vga_text_fini ();
grub_stop_floppy ();
}

View file

@ -35,7 +35,8 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_efi_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_efi_fini ();
}

View file

@ -239,8 +239,9 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_console_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_console_fini ();
grub_stop_floppy ();
}

View file

@ -277,8 +277,9 @@ grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_vga_text_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_vga_text_fini ();
grub_stop_floppy ();
}

View file

@ -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
}

View 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

View 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):

View file

@ -68,9 +68,10 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_efi_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
grub_efi_fini ();
}
void

View file

@ -298,10 +298,13 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags)
{
grub_ofdisk_fini ();
grub_console_fini ();
if (flags & GRUB_LOADER_FLAG_NORETURN)
{
grub_ofdisk_fini ();
grub_console_fini ();
}
}
grub_uint64_t

View file

@ -259,7 +259,7 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags __attribute__ ((unused)))
{
}

View file

@ -217,7 +217,7 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags __attribute__ ((unused)))
{
}

View file

@ -70,7 +70,7 @@ grub_machine_init (void)
}
void
grub_machine_fini (void)
grub_machine_fini (int flags __attribute__ ((unused)))
{
}

View 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

View 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
View 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;
}

View file

@ -58,4 +58,3 @@ grub_reboot (void)
while (1);
}

View file

@ -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,

View 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));
}

View 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)

View file

@ -250,6 +250,9 @@ static struct legacy_command legacy_commands[] =
{"pause", "echo %s; if ! sleep -i 60; then return; fi\n", NULL, 0, 1,
{TYPE_REST_VERBATIM}, 0,
"[MESSAGE ...]", "Print MESSAGE, then wait until a key is pressed."},
{"print", "echo %s\n", NULL, 0, 1,
{TYPE_REST_VERBATIM}, 0,
"[MESSAGE ...]", "Print MESSAGE."},
/* FIXME: quit unsupported. */
/* FIXME: rarp unsupported. */
{"read", "read_dword %s\n", NULL, 0, 1, {TYPE_INT}, 0, "ADDR",

View file

@ -1432,7 +1432,7 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel,
#ifdef GRUB_MACHINE_EFI
grub_efi_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx,
avoid_efi_boot_services);
#elif defined (__powerpc__)
#elif defined (__powerpc__) || defined (GRUB_MACHINE_XEN)
(void) avoid_efi_boot_services;
grub_machine_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx);
#else

View 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)

View 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
View 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 (;;);
}

View 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 (;;);
}

View 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
View 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);
}

View 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");
}

View 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"

View 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"

View 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");
}

View 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");
}