Accepting request 436663 from home:michael-chang:branches:Base:System

- From Juergen Gross <jgross@suse.com>: grub-xen: support booting huge
  pv-domains (bsc#1004398) (bsc#899465)
  * 0001-xen-make-xen-loader-callable-multiple-times.patch
  * 0002-xen-avoid-memleaks-on-error.patch
  * 0003-xen-reduce-number-of-global-variables-in-xen-loader.patch
  * 0004-xen-add-elfnote.h-to-avoid-using-numbers-instead-of-.patch
  * 0005-xen-synchronize-xen-header.patch
  * 0006-xen-factor-out-p2m-list-allocation-into-separate-fun.patch
  * 0007-xen-factor-out-allocation-of-special-pages-into-sepa.patch
  * 0008-xen-factor-out-allocation-of-page-tables-into-separa.patch
  * 0009-xen-add-capability-to-load-initrd-outside-of-initial.patch
  * 0010-xen-modify-page-table-construction.patch
  * 0011-xen-add-capability-to-load-p2m-list-outside-of-kerne.patch

OBS-URL: https://build.opensuse.org/request/show/436663
OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=236
This commit is contained in:
Andrei Borzenkov 2016-10-24 17:26:09 +00:00 committed by Git OBS Bridge
parent 98cebe696e
commit 8da1cb3353
13 changed files with 3230 additions and 0 deletions

View File

@ -0,0 +1,83 @@
From 3fcf47254678ddd9387b8ee80f21ad5f163cb7a9 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:06 +0100
Subject: [PATCH 01/11] xen: make xen loader callable multiple times
The loader for xen paravirtualized environment isn't callable multiple
times as it won't free any memory in case of failure.
Call grub_relocator_unload() as other modules do it before allocating
a new relocator or when unloading the module.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index c4d9689..179e89c 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -316,11 +316,23 @@ grub_xen_boot (void)
xen_inf.virt_base);
}
+static void
+grub_xen_reset (void)
+{
+ grub_memset (&next_start, 0, sizeof (next_start));
+ xen_module_info_page = NULL;
+ n_modules = 0;
+
+ grub_relocator_unload (relocator);
+ relocator = NULL;
+ loaded = 0;
+}
+
static grub_err_t
grub_xen_unload (void)
{
+ grub_xen_reset ();
grub_dl_unref (my_mod);
- loaded = 0;
return GRUB_ERR_NONE;
}
@@ -403,10 +415,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
grub_loader_unset ();
- grub_memset (&next_start, 0, sizeof (next_start));
-
- xen_module_info_page = NULL;
- n_modules = 0;
+ grub_xen_reset ();
grub_create_loader_cmdline (argc - 1, argv + 1,
(char *) next_start.cmd_line,
@@ -503,16 +512,18 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
goto fail;
fail:
+ /* grub_errno might be clobbered by further calls, save the error reason. */
+ err = grub_errno;
if (elf)
grub_elf_close (elf);
else if (file)
grub_file_close (file);
- if (grub_errno != GRUB_ERR_NONE)
- loaded = 0;
+ if (err != GRUB_ERR_NONE)
+ grub_xen_reset ();
- return grub_errno;
+ return err;
}
static grub_err_t
--
2.6.6

View File

@ -0,0 +1,101 @@
From da05ded53eea9316b03f0e00dff3a8c9c4661c95 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:07 +0100
Subject: [PATCH 02/11] xen: avoid memleaks on error
When loading a Xen pv-kernel avoid memory leaks in case of errors.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 2 +-
grub-core/loader/i386/xen_fileXX.c | 19 +++++++++++++------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index 179e89c..f45f70f 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -563,7 +563,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
{
err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
if (err)
- return err;
+ goto fail;
if (grub_initrd_load (&initrd_ctx, argv,
get_virtual_current_address (ch)))
diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
index 1ba5649..36b40e4 100644
--- a/grub-core/loader/i386/xen_fileXX.c
+++ b/grub-core/loader/i386/xen_fileXX.c
@@ -26,6 +26,8 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
char *buf;
char *ptr;
int has_paddr = 0;
+
+ grub_errno = GRUB_ERR_NONE;
if (grub_file_seek (elf->file, off) == (grub_off_t) -1)
return grub_errno;
buf = grub_malloc (sz);
@@ -35,7 +37,8 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
if (grub_file_read (elf->file, buf, sz) != (grub_ssize_t) sz)
{
if (grub_errno)
- return grub_errno;
+ goto out;
+ grub_free (buf);
return grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
elf->file->name);
}
@@ -123,14 +126,14 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
{
xi->virt_base = grub_strtoull (ptr + sizeof ("VIRT_BASE=") - 1, &ptr, 16);
if (grub_errno)
- return grub_errno;
+ goto out;
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;
+ goto out;
continue;
}
if (grub_strncmp (ptr, "HYPERCALL_PAGE=", sizeof ("HYPERCALL_PAGE=") - 1) == 0)
@@ -138,7 +141,7 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
xi->hypercall_page = grub_strtoull (ptr + sizeof ("HYPERCALL_PAGE=") - 1, &ptr, 16);
xi->has_hypercall_page = 1;
if (grub_errno)
- return grub_errno;
+ goto out;
continue;
}
if (grub_strncmp (ptr, "ELF_PADDR_OFFSET=", sizeof ("ELF_PADDR_OFFSET=") - 1) == 0)
@@ -146,7 +149,7 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
xi->paddr_offset = grub_strtoull (ptr + sizeof ("ELF_PADDR_OFFSET=") - 1, &ptr, 16);
has_paddr = 1;
if (grub_errno)
- return grub_errno;
+ goto out;
continue;
}
}
@@ -154,7 +157,11 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
xi->hypercall_page = (xi->hypercall_page << 12) + xi->virt_base;
if (!has_paddr)
xi->paddr_offset = xi->virt_base;
- return GRUB_ERR_NONE;
+
+out:
+ grub_free (buf);
+
+ return grub_errno;
}
#pragma GCC diagnostic ignored "-Wcast-align"
--
2.6.6

View File

@ -0,0 +1,509 @@
From d0c3974a455c50de4bc6b6fa8ef9b280a6f99faa Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:08 +0100
Subject: [PATCH 03/11] xen: reduce number of global variables in xen loader
The loader for xen paravirtualized environment is using lots of global
variables. Reduce the number by making them either local or by putting
them into a single state structure.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 267 +++++++++++++++++++++++---------------------
1 file changed, 142 insertions(+), 125 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index f45f70f..691c22e 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -42,16 +42,20 @@
GRUB_MOD_LICENSE ("GPLv3+");
-static struct grub_relocator *relocator = NULL;
-static grub_uint64_t max_addr;
+struct xen_loader_state {
+ struct grub_relocator *relocator;
+ struct start_info next_start;
+ struct grub_xen_file_info xen_inf;
+ grub_uint64_t max_addr;
+ struct xen_multiboot_mod_list *module_info_page;
+ grub_uint64_t modules_target_start;
+ grub_size_t n_modules;
+ int loaded;
+};
+
+static struct xen_loader_state xen_state;
+
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))
@@ -225,50 +229,55 @@ grub_xen_boot (void)
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? */
+ state.mfn_list = xen_state.max_addr;
+ xen_state.next_start.mfn_list =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ xen_state.next_start.first_p2m_pfn = xen_state.max_addr >> PAGE_SHIFT;
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;
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr, pgtsize);
+ xen_state.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);
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + pgtsize, PAGE_SIZE);
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- max_addr, sizeof (next_start));
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr,
+ sizeof (xen_state.next_start));
if (err)
return err;
- state.start_info = max_addr + xen_inf.virt_base;
+ state.start_info = xen_state.max_addr + xen_state.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);
+ xen_state.max_addr =
+ ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), PAGE_SIZE);
+
+ xen_state.next_start.nr_pages = grub_xen_start_page_addr->nr_pages;
+ grub_memcpy (xen_state.next_start.magic, grub_xen_start_page_addr->magic,
+ sizeof (xen_state.next_start.magic));
+ xen_state.next_start.store_mfn = grub_xen_start_page_addr->store_mfn;
+ xen_state.next_start.store_evtchn = grub_xen_start_page_addr->store_evtchn;
+ xen_state.next_start.console.domU = grub_xen_start_page_addr->console.domU;
+ xen_state.next_start.shared_info = grub_xen_start_page_addr->shared_info;
+
+ err = set_mfns (new_mfn_list, xen_state.max_addr >> PAGE_SHIFT);
if (err)
return err;
- max_addr += 2 * PAGE_SIZE;
+ xen_state.max_addr += 2 * PAGE_SIZE;
- next_start.pt_base = max_addr + xen_inf.virt_base;
- state.paging_start = max_addr >> PAGE_SHIFT;
+ xen_state.next_start.pt_base =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ state.paging_start = xen_state.max_addr >> PAGE_SHIFT;
- nr_info_pages = max_addr >> PAGE_SHIFT;
+ nr_info_pages = xen_state.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_pt_pages = get_pgtable_size (nr_pages, xen_state.xen_inf.virt_base);
nr_need_pages =
nr_info_pages + nr_pt_pages +
((ADDITIONAL_SIZE + STACK_SIZE) >> PAGE_SHIFT);
@@ -278,27 +287,28 @@ grub_xen_boot (void)
}
grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
- (unsigned long long) xen_inf.virt_base,
+ (unsigned long long) xen_state.xen_inf.virt_base,
(unsigned long long) page2offset (nr_pages));
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- max_addr, page2offset (nr_pt_pages));
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.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);
+ xen_state.max_addr >> PAGE_SHIFT, nr_pages,
+ xen_state.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;
+ xen_state.max_addr += page2offset (nr_pt_pages);
+ state.stack = xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
+ state.entry_point = xen_state.xen_inf.entry_point;
- next_start.nr_p2m_frames += nr_pt_pages;
- next_start.nr_pt_frames = nr_pt_pages;
+ xen_state.next_start.nr_p2m_frames += nr_pt_pages;
+ xen_state.next_start.nr_pt_frames = nr_pt_pages;
state.paging_size = nr_pt_pages;
- *nst = next_start;
+ *nst = xen_state.next_start;
grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
@@ -308,24 +318,20 @@ grub_xen_boot (void)
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 <
+ return grub_relocator_xen_boot (xen_state.relocator, state, nr_pages,
+ xen_state.xen_inf.virt_base <
PAGE_SIZE ? page2offset (nr_pages) : 0,
nr_pages - 1,
page2offset (nr_pages - 1) +
- xen_inf.virt_base);
+ xen_state.xen_inf.virt_base);
}
static void
grub_xen_reset (void)
{
- grub_memset (&next_start, 0, sizeof (next_start));
- xen_module_info_page = NULL;
- n_modules = 0;
+ grub_relocator_unload (xen_state.relocator);
- grub_relocator_unload (relocator);
- relocator = NULL;
- loaded = 0;
+ grub_memset (&xen_state, 0, sizeof (xen_state));
}
static grub_err_t
@@ -409,17 +415,22 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
grub_file_t file;
grub_elf_t elf;
grub_err_t err;
+ void *kern_chunk_src;
+ grub_relocator_chunk_t ch;
+ grub_addr_t kern_start;
+ grub_addr_t kern_end;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ /* Call grub_loader_unset early to avoid it being called by grub_loader_set */
grub_loader_unset ();
grub_xen_reset ();
grub_create_loader_cmdline (argc - 1, argv + 1,
- (char *) next_start.cmd_line,
- sizeof (next_start.cmd_line) - 1);
+ (char *) xen_state.next_start.cmd_line,
+ sizeof (xen_state.next_start.cmd_line) - 1);
file = grub_file_open (argv[0]);
if (!file)
@@ -429,85 +440,82 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
if (!elf)
goto fail;
- err = grub_xen_get_info (elf, &xen_inf);
+ err = grub_xen_get_info (elf, &xen_state.xen_inf);
if (err)
goto fail;
#ifdef __x86_64__
- if (xen_inf.arch != GRUB_XEN_FILE_X86_64)
+ if (xen_state.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)
+ if (xen_state.xen_inf.arch != GRUB_XEN_FILE_I386_PAE
+ && xen_state.xen_inf.arch != GRUB_XEN_FILE_I386_PAE_BIMODE)
#endif
{
grub_error (GRUB_ERR_BAD_OS, "incompatible architecture: %d",
- xen_inf.arch);
+ xen_state.xen_inf.arch);
goto fail;
}
- if (xen_inf.virt_base & (PAGE_SIZE - 1))
+ if (xen_state.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);
+ (unsigned long long) xen_state.xen_inf.virt_base,
+ (unsigned long long) xen_state.xen_inf.entry_point);
- relocator = grub_relocator_new ();
- if (!relocator)
+ xen_state.relocator = grub_relocator_new ();
+ if (!xen_state.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;
+ kern_start = xen_state.xen_inf.kern_start - xen_state.xen_inf.paddr_offset;
+ kern_end = xen_state.xen_inf.kern_end - xen_state.xen_inf.paddr_offset;
- if (xen_inf.has_hypercall_page)
+ if (xen_state.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;
+ (unsigned long long) xen_state.xen_inf.hypercall_page);
+ kern_start = grub_min (kern_start, xen_state.xen_inf.hypercall_page -
+ xen_state.xen_inf.virt_base);
+ kern_end = grub_max (kern_end, xen_state.xen_inf.hypercall_page -
+ xen_state.xen_inf.virt_base + PAGE_SIZE);
}
- max_addr = ALIGN_UP (kern_end, PAGE_SIZE);
+ xen_state.max_addr = ALIGN_UP (kern_end, PAGE_SIZE);
- err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start,
+ err = grub_relocator_alloc_chunk_addr (xen_state.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);
+ (unsigned long long) xen_state.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);
+ (unsigned long long) xen_state.xen_inf.kern_start,
+ (unsigned long long) xen_state.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);
+ - xen_state.xen_inf.paddr_offset, 0, 0, 0);
- if (xen_inf.has_hypercall_page)
+ if (xen_state.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);
+ xen_state.xen_inf.hypercall_page -
+ xen_state.xen_inf.virt_base - kern_start, i);
}
if (err)
goto fail;
grub_dl_ref (my_mod);
- loaded = 1;
+ xen_state.loaded = 1;
grub_loader_set (grub_xen_boot, grub_xen_unload, 0);
- loaded = 1;
goto fail;
@@ -541,14 +549,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- if (!loaded)
+ if (!xen_state.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)
+ if (xen_state.next_start.mod_start || xen_state.next_start.mod_len)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("initrd already loaded"));
goto fail;
@@ -561,7 +569,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
if (size)
{
- err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr, size);
if (err)
goto fail;
@@ -570,13 +579,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- next_start.mod_start = max_addr + xen_inf.virt_base;
- next_start.mod_len = size;
+ xen_state.next_start.mod_start =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ xen_state.next_start.mod_len = size;
- max_addr = ALIGN_UP (max_addr + size, PAGE_SIZE);
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE);
grub_dprintf ("xen", "Initrd, addr=0x%x, size=0x%x\n",
- (unsigned) next_start.mod_start, (unsigned) size);
+ (unsigned) xen_state.next_start.mod_start, (unsigned) size);
fail:
grub_initrd_close (&initrd_ctx);
@@ -608,45 +618,48 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- if (!loaded)
+ if (!xen_state.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)
+ if ((xen_state.next_start.mod_start || xen_state.next_start.mod_len) &&
+ !xen_state.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)
+ if (xen_state.n_modules >= MAX_MODULES - 1)
{
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many modules");
}
- if (!xen_module_info_page)
+ if (!xen_state.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
+ xen_state.n_modules = 0;
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE);
+ xen_state.modules_target_start = xen_state.max_addr;
+ xen_state.next_start.mod_start =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ xen_state.next_start.flags |= SIF_MULTIBOOT_MOD;
+
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr, MAX_MODULES
*
- sizeof (xen_module_info_page
+ sizeof (xen_state.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]);
+ xen_state.module_info_page = get_virtual_current_address (ch);
+ grub_memset (xen_state.module_info_page, 0, MAX_MODULES
+ * sizeof (xen_state.module_info_page[0]));
+ xen_state.max_addr +=
+ MAX_MODULES * sizeof (xen_state.module_info_page[0]);
}
- max_addr = ALIGN_UP (max_addr, PAGE_SIZE);
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE);
if (nounzip)
grub_file_filter_disable_compression ();
@@ -657,20 +670,22 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1);
- err = grub_relocator_alloc_chunk_addr (relocator, &ch,
- max_addr, cmdline_len);
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.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);
+ xen_state.module_info_page[xen_state.n_modules].cmdline =
+ xen_state.max_addr - xen_state.modules_target_start;
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + cmdline_len, PAGE_SIZE);
if (size)
{
- err = grub_relocator_alloc_chunk_addr (relocator, &ch, max_addr, size);
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr, size);
if (err)
goto fail;
if (grub_file_read (file, get_virtual_current_address (ch), size)
@@ -682,15 +697,17 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
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++;
+ xen_state.next_start.mod_len =
+ xen_state.max_addr + size - xen_state.modules_target_start;
+ xen_state.module_info_page[xen_state.n_modules].mod_start =
+ xen_state.max_addr - xen_state.modules_target_start;
+ xen_state.module_info_page[xen_state.n_modules].mod_end =
+ xen_state.max_addr + size - xen_state.modules_target_start;
+
+ xen_state.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);
+ (unsigned) xen_state.max_addr, (unsigned) size);
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE);
fail:
--
2.6.6

View File

@ -0,0 +1,368 @@
From 0c3821e10ca0a47c436e3aacb230c47412cf517f Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:09 +0100
Subject: [PATCH 04/11] xen: add elfnote.h to avoid using numbers instead of
constants
Various features and parameters of a pv-kernel are specified via
elf notes in the kernel image. Those notes are part of the interface
between the Xen hypervisor and the kernel.
Instead of using num,bers in the code when interpreting the elf notes
make use of the header supplied by Xen for that purpose.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen_fileXX.c | 19 +--
include/xen/elfnote.h | 281 +++++++++++++++++++++++++++++++++++++
2 files changed, 291 insertions(+), 9 deletions(-)
create mode 100644 include/xen/elfnote.h
diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
index 36b40e4..03215ca 100644
--- a/grub-core/loader/i386/xen_fileXX.c
+++ b/grub-core/loader/i386/xen_fileXX.c
@@ -18,6 +18,7 @@
#include <grub/xen_file.h>
#include <grub/misc.h>
+#include <xen/elfnote.h>
static grub_err_t
parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
@@ -203,35 +204,35 @@ parse_note (grub_elf_t elf, struct grub_xen_file_info *xi,
xi->has_note = 1;
switch (nh->n_type)
{
- case 1:
+ case XEN_ELFNOTE_ENTRY:
xi->entry_point = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
break;
- case 2:
+ case XEN_ELFNOTE_HYPERCALL_PAGE:
xi->hypercall_page = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
xi->has_hypercall_page = 1;
break;
- case 3:
+ case XEN_ELFNOTE_VIRT_BASE:
xi->virt_base = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
break;
- case 4:
+ case XEN_ELFNOTE_PADDR_OFFSET:
xi->paddr_offset = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
break;
- case 5:
+ case XEN_ELFNOTE_XEN_VERSION:
grub_dprintf ("xen", "xenversion = `%s'\n", (char *) desc);
break;
- case 6:
+ case XEN_ELFNOTE_GUEST_OS:
grub_dprintf ("xen", "name = `%s'\n", (char *) desc);
break;
- case 7:
+ case XEN_ELFNOTE_GUEST_VERSION:
grub_dprintf ("xen", "version = `%s'\n", (char *) desc);
break;
- case 8:
+ case XEN_ELFNOTE_LOADER:
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:
+ case XEN_ELFNOTE_PAE_MODE:
grub_dprintf ("xen", "pae = `%s', %d, %d\n", (char *) desc,
xi->arch, descsz);
if (xi->arch != GRUB_XEN_FILE_I386
diff --git a/include/xen/elfnote.h b/include/xen/elfnote.h
new file mode 100644
index 0000000..353985f
--- /dev/null
+++ b/include/xen/elfnote.h
@@ -0,0 +1,281 @@
+/******************************************************************************
+ * elfnote.h
+ *
+ * Definitions used for the Xen ELF notes.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
+ */
+
+#ifndef __XEN_PUBLIC_ELFNOTE_H__
+#define __XEN_PUBLIC_ELFNOTE_H__
+
+/*
+ * `incontents 200 elfnotes ELF notes
+ *
+ * The notes should live in a PT_NOTE segment and have "Xen" in the
+ * name field.
+ *
+ * Numeric types are either 4 or 8 bytes depending on the content of
+ * the desc field.
+ *
+ * LEGACY indicated the fields in the legacy __xen_guest string which
+ * this a note type replaces.
+ *
+ * String values (for non-legacy) are NULL terminated ASCII, also known
+ * as ASCIZ type.
+ */
+
+/*
+ * NAME=VALUE pair (string).
+ */
+#define XEN_ELFNOTE_INFO 0
+
+/*
+ * The virtual address of the entry point (numeric).
+ *
+ * LEGACY: VIRT_ENTRY
+ */
+#define XEN_ELFNOTE_ENTRY 1
+
+/* The virtual address of the hypercall transfer page (numeric).
+ *
+ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
+ * number not a virtual address)
+ */
+#define XEN_ELFNOTE_HYPERCALL_PAGE 2
+
+/* The virtual address where the kernel image should be mapped (numeric).
+ *
+ * Defaults to 0.
+ *
+ * LEGACY: VIRT_BASE
+ */
+#define XEN_ELFNOTE_VIRT_BASE 3
+
+/*
+ * The offset of the ELF paddr field from the actual required
+ * pseudo-physical address (numeric).
+ *
+ * This is used to maintain backwards compatibility with older kernels
+ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
+ * if not present.
+ *
+ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
+ */
+#define XEN_ELFNOTE_PADDR_OFFSET 4
+
+/*
+ * The version of Xen that we work with (string).
+ *
+ * LEGACY: XEN_VER
+ */
+#define XEN_ELFNOTE_XEN_VERSION 5
+
+/*
+ * The name of the guest operating system (string).
+ *
+ * LEGACY: GUEST_OS
+ */
+#define XEN_ELFNOTE_GUEST_OS 6
+
+/*
+ * The version of the guest operating system (string).
+ *
+ * LEGACY: GUEST_VER
+ */
+#define XEN_ELFNOTE_GUEST_VERSION 7
+
+/*
+ * The loader type (string).
+ *
+ * LEGACY: LOADER
+ */
+#define XEN_ELFNOTE_LOADER 8
+
+/*
+ * The kernel supports PAE (x86/32 only, string = "yes", "no" or
+ * "bimodal").
+ *
+ * For compatibility with Xen 3.0.3 and earlier the "bimodal" setting
+ * may be given as "yes,bimodal" which will cause older Xen to treat
+ * this kernel as PAE.
+ *
+ * LEGACY: PAE (n.b. The legacy interface included a provision to
+ * indicate 'extended-cr3' support allowing L3 page tables to be
+ * placed above 4G. It is assumed that any kernel new enough to use
+ * these ELF notes will include this and therefore "yes" here is
+ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
+ */
+#define XEN_ELFNOTE_PAE_MODE 9
+
+/*
+ * The features supported/required by this kernel (string).
+ *
+ * The string must consist of a list of feature names (as given in
+ * features.h, without the "XENFEAT_" prefix) separated by '|'
+ * characters. If a feature is required for the kernel to function
+ * then the feature name must be preceded by a '!' character.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_FEATURES 10
+
+/*
+ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
+ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
+ * of this string as a boolean flag rather than requiring "yes" or
+ * "no".
+ */
+#define XEN_ELFNOTE_BSD_SYMTAB 11
+
+/*
+ * The lowest address the hypervisor hole can begin at (numeric).
+ *
+ * This must not be set higher than HYPERVISOR_VIRT_START. Its presence
+ * also indicates to the hypervisor that the kernel can deal with the
+ * hole starting at a higher address.
+ */
+#define XEN_ELFNOTE_HV_START_LOW 12
+
+/*
+ * List of maddr_t-sized mask/value pairs describing how to recognize
+ * (non-present) L1 page table entries carrying valid MFNs (numeric).
+ */
+#define XEN_ELFNOTE_L1_MFN_VALID 13
+
+/*
+ * Whether or not the guest supports cooperative suspend cancellation.
+ * This is a numeric value.
+ *
+ * Default is 0
+ */
+#define XEN_ELFNOTE_SUSPEND_CANCEL 14
+
+/*
+ * The (non-default) location the initial phys-to-machine map should be
+ * placed at by the hypervisor (Dom0) or the tools (DomU).
+ * The kernel must be prepared for this mapping to be established using
+ * large pages, despite such otherwise not being available to guests.
+ * The kernel must also be able to handle the page table pages used for
+ * this mapping not being accessible through the initial mapping.
+ * (Only x86-64 supports this at present.)
+ */
+#define XEN_ELFNOTE_INIT_P2M 15
+
+/*
+ * Whether or not the guest can deal with being passed an initrd not
+ * mapped through its initial page tables.
+ */
+#define XEN_ELFNOTE_MOD_START_PFN 16
+
+/*
+ * The features supported by this kernel (numeric).
+ *
+ * Other than XEN_ELFNOTE_FEATURES on pre-4.2 Xen, this note allows a
+ * kernel to specify support for features that older hypervisors don't
+ * know about. The set of features 4.2 and newer hypervisors will
+ * consider supported by the kernel is the combination of the sets
+ * specified through this and the string note.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_SUPPORTED_FEATURES 17
+
+/*
+ * Physical entry point into the kernel.
+ *
+ * 32bit entry point into the kernel. When requested to launch the
+ * guest kernel in a HVM container, Xen will use this entry point to
+ * launch the guest in 32bit protected mode with paging disabled.
+ * Ignored otherwise.
+ */
+#define XEN_ELFNOTE_PHYS32_ENTRY 18
+
+/*
+ * The number of the highest elfnote defined.
+ */
+#define XEN_ELFNOTE_MAX XEN_ELFNOTE_PHYS32_ENTRY
+
+/*
+ * System information exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO
+ * note in case of a system crash. This note will contain various
+ * information about the system, see xen/include/xen/elfcore.h.
+ */
+#define XEN_ELFNOTE_CRASH_INFO 0x1000001
+
+/*
+ * System registers exported through crash notes.
+ *
+ * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS
+ * note per cpu in case of a system crash. This note is architecture
+ * specific and will contain registers not saved in the "CORE" note.
+ * See xen/include/xen/elfcore.h for more information.
+ */
+#define XEN_ELFNOTE_CRASH_REGS 0x1000002
+
+
+/*
+ * xen dump-core none note.
+ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_NONE
+ * in its dump file to indicate that the file is xen dump-core
+ * file. This note doesn't have any other information.
+ * See tools/libxc/xc_core.h for more information.
+ */
+#define XEN_ELFNOTE_DUMPCORE_NONE 0x2000000
+
+/*
+ * xen dump-core header note.
+ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_HEADER
+ * in its dump file.
+ * See tools/libxc/xc_core.h for more information.
+ */
+#define XEN_ELFNOTE_DUMPCORE_HEADER 0x2000001
+
+/*
+ * xen dump-core xen version note.
+ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_XEN_VERSION
+ * in its dump file. It contains the xen version obtained via the
+ * XENVER hypercall.
+ * See tools/libxc/xc_core.h for more information.
+ */
+#define XEN_ELFNOTE_DUMPCORE_XEN_VERSION 0x2000002
+
+/*
+ * xen dump-core format version note.
+ * xm dump-core code will create one XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION
+ * in its dump file. It contains a format version identifier.
+ * See tools/libxc/xc_core.h for more information.
+ */
+#define XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION 0x2000003
+
+#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.6.6

View File

@ -0,0 +1,342 @@
From 21078a54248f25f9831c3b1007bec0cbfbd720a7 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:10 +0100
Subject: [PATCH 05/11] xen: synchronize xen header
Get actual version of include/xen/xen.h from the Xen repository in
order to be able to use constants defined there.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/xen/arch-x86/xen-x86_32.h | 22 +++----
include/xen/arch-x86/xen-x86_64.h | 8 +--
include/xen/xen.h | 125 +++++++++++++++++++++++++++-----------
3 files changed, 105 insertions(+), 50 deletions(-)
diff --git a/include/xen/arch-x86/xen-x86_32.h b/include/xen/arch-x86/xen-x86_32.h
index 1504191..7eca6cd 100644
--- a/include/xen/arch-x86/xen-x86_32.h
+++ b/include/xen/arch-x86/xen-x86_32.h
@@ -58,34 +58,31 @@
#define __HYPERVISOR_VIRT_START_PAE 0xF5800000
#define __MACH2PHYS_VIRT_START_PAE 0xF5800000
#define __MACH2PHYS_VIRT_END_PAE 0xF6800000
-#define HYPERVISOR_VIRT_START_PAE \
- mk_unsigned_long(__HYPERVISOR_VIRT_START_PAE)
-#define MACH2PHYS_VIRT_START_PAE \
- mk_unsigned_long(__MACH2PHYS_VIRT_START_PAE)
-#define MACH2PHYS_VIRT_END_PAE \
- mk_unsigned_long(__MACH2PHYS_VIRT_END_PAE)
+#define HYPERVISOR_VIRT_START_PAE xen_mk_ulong(__HYPERVISOR_VIRT_START_PAE)
+#define MACH2PHYS_VIRT_START_PAE xen_mk_ulong(__MACH2PHYS_VIRT_START_PAE)
+#define MACH2PHYS_VIRT_END_PAE xen_mk_ulong(__MACH2PHYS_VIRT_END_PAE)
/* Non-PAE bounds are obsolete. */
#define __HYPERVISOR_VIRT_START_NONPAE 0xFC000000
#define __MACH2PHYS_VIRT_START_NONPAE 0xFC000000
#define __MACH2PHYS_VIRT_END_NONPAE 0xFC400000
#define HYPERVISOR_VIRT_START_NONPAE \
- mk_unsigned_long(__HYPERVISOR_VIRT_START_NONPAE)
+ xen_mk_ulong(__HYPERVISOR_VIRT_START_NONPAE)
#define MACH2PHYS_VIRT_START_NONPAE \
- mk_unsigned_long(__MACH2PHYS_VIRT_START_NONPAE)
+ xen_mk_ulong(__MACH2PHYS_VIRT_START_NONPAE)
#define MACH2PHYS_VIRT_END_NONPAE \
- mk_unsigned_long(__MACH2PHYS_VIRT_END_NONPAE)
+ xen_mk_ulong(__MACH2PHYS_VIRT_END_NONPAE)
#define __HYPERVISOR_VIRT_START __HYPERVISOR_VIRT_START_PAE
#define __MACH2PHYS_VIRT_START __MACH2PHYS_VIRT_START_PAE
#define __MACH2PHYS_VIRT_END __MACH2PHYS_VIRT_END_PAE
#ifndef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
+#define HYPERVISOR_VIRT_START xen_mk_ulong(__HYPERVISOR_VIRT_START)
#endif
-#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
-#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_VIRT_START xen_mk_ulong(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END xen_mk_ulong(__MACH2PHYS_VIRT_END)
#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>2)
#ifndef machine_to_phys_mapping
#define machine_to_phys_mapping ((unsigned long *)MACH2PHYS_VIRT_START)
@@ -104,6 +101,7 @@
do { if ( sizeof(hnd) == 8 ) *(uint64_t *)&(hnd) = 0; \
(hnd).p = val; \
} while ( 0 )
+#define int64_aligned_t int64_t __attribute__((aligned(8)))
#define uint64_aligned_t uint64_t __attribute__((aligned(8)))
#define __XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name
#define XEN_GUEST_HANDLE_64(name) __XEN_GUEST_HANDLE_64(name)
diff --git a/include/xen/arch-x86/xen-x86_64.h b/include/xen/arch-x86/xen-x86_64.h
index 1c4e159..5e18613 100644
--- a/include/xen/arch-x86/xen-x86_64.h
+++ b/include/xen/arch-x86/xen-x86_64.h
@@ -76,12 +76,12 @@
#define __MACH2PHYS_VIRT_END 0xFFFF804000000000
#ifndef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
-#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END)
+#define HYPERVISOR_VIRT_START xen_mk_ulong(__HYPERVISOR_VIRT_START)
+#define HYPERVISOR_VIRT_END xen_mk_ulong(__HYPERVISOR_VIRT_END)
#endif
-#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START)
-#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_VIRT_START xen_mk_ulong(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END xen_mk_ulong(__MACH2PHYS_VIRT_END)
#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
#ifndef machine_to_phys_mapping
#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
diff --git a/include/xen/xen.h b/include/xen/xen.h
index a6a2092..6c9e42b 100644
--- a/include/xen/xen.h
+++ b/include/xen/xen.h
@@ -52,6 +52,19 @@ DEFINE_XEN_GUEST_HANDLE(void);
DEFINE_XEN_GUEST_HANDLE(uint64_t);
DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
+
+/* Turn a plain number into a C unsigned (long) constant. */
+#define __xen_mk_uint(x) x ## U
+#define __xen_mk_ulong(x) x ## UL
+#define xen_mk_uint(x) __xen_mk_uint(x)
+#define xen_mk_ulong(x) __xen_mk_ulong(x)
+
+#else
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define xen_mk_uint(x) x
+#define xen_mk_ulong(x) x
+
#endif
/*
@@ -101,6 +114,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
#define __HYPERVISOR_kexec_op 37
#define __HYPERVISOR_tmem_op 38
#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
+#define __HYPERVISOR_xenpmu_op 40
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
@@ -160,6 +174,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
#define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */
#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */
#define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */
+#define VIRQ_XENPMU 13 /* V. PMC interrupt */
/* Architecture-specific VIRQ definitions. */
#define VIRQ_ARCH_0 16
@@ -449,13 +464,13 @@ DEFINE_XEN_GUEST_HANDLE(mmuext_op_t);
/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */
/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */
/* ` enum uvm_flags { */
-#define UVMF_NONE (0UL<<0) /* No flushing at all. */
-#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */
-#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */
-#define UVMF_FLUSHTYPE_MASK (3UL<<0)
-#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */
-#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */
-#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */
+#define UVMF_NONE (xen_mk_ulong(0)<<0) /* No flushing at all. */
+#define UVMF_TLB_FLUSH (xen_mk_ulong(1)<<0) /* Flush entire TLB(s). */
+#define UVMF_INVLPG (xen_mk_ulong(2)<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK (xen_mk_ulong(3)<<0)
+#define UVMF_MULTI (xen_mk_ulong(0)<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL (xen_mk_ulong(0)<<2) /* Flush local TLB. */
+#define UVMF_ALL (xen_mk_ulong(1)<<2) /* Flush all TLBs. */
/* ` } */
/*
@@ -486,17 +501,27 @@ DEFINE_XEN_GUEST_HANDLE(mmuext_op_t);
/* x86/PAE guests: support PDPTs above 4GB. */
#define VMASST_TYPE_pae_extended_cr3 3
-#define MAX_VMASST_TYPE 3
-
-#ifndef __ASSEMBLY__
+/*
+ * x86/64 guests: strictly hide M2P from user mode.
+ * This allows the guest to control respective hypervisor behavior:
+ * - when not set, L4 tables get created with the respective slot blank,
+ * and whenever the L4 table gets used as a kernel one the missing
+ * mapping gets inserted,
+ * - when set, L4 tables get created with the respective slot initialized
+ * as before, and whenever the L4 table gets used as a user one the
+ * mapping gets zapped.
+ */
+#define VMASST_TYPE_m2p_strict 32
-typedef uint16_t domid_t;
+#if __XEN_INTERFACE_VERSION__ < 0x00040600
+#define MAX_VMASST_TYPE 3
+#endif
/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
-#define DOMID_FIRST_RESERVED (0x7FF0U)
+#define DOMID_FIRST_RESERVED xen_mk_uint(0x7FF0)
/* DOMID_SELF is used in certain contexts to refer to oneself. */
-#define DOMID_SELF (0x7FF0U)
+#define DOMID_SELF xen_mk_uint(0x7FF0)
/*
* DOMID_IO is used to restrict page-table updates to mapping I/O memory.
@@ -507,7 +532,7 @@ typedef uint16_t domid_t;
* This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
* be specified by any calling domain.
*/
-#define DOMID_IO (0x7FF1U)
+#define DOMID_IO xen_mk_uint(0x7FF1)
/*
* DOMID_XEN is used to allow privileged domains to map restricted parts of
@@ -515,17 +540,21 @@ typedef uint16_t domid_t;
* This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
* the caller is privileged.
*/
-#define DOMID_XEN (0x7FF2U)
+#define DOMID_XEN xen_mk_uint(0x7FF2)
/*
* DOMID_COW is used as the owner of sharable pages */
-#define DOMID_COW (0x7FF3U)
+#define DOMID_COW xen_mk_uint(0x7FF3)
/* DOMID_INVALID is used to identify pages with unknown owner. */
-#define DOMID_INVALID (0x7FF4U)
+#define DOMID_INVALID xen_mk_uint(0x7FF4)
/* Idle domain. */
-#define DOMID_IDLE (0x7FFFU)
+#define DOMID_IDLE xen_mk_uint(0x7FFF)
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
/*
* Send an array of these to HYPERVISOR_mmu_update().
@@ -682,6 +711,12 @@ struct shared_info {
uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
+#if !defined(__i386__)
+ uint32_t wc_sec_hi;
+# define xen_wc_sec_hi wc_sec_hi
+#elif !defined(__XEN__) && !defined(__XEN_TOOLS__)
+# define xen_wc_sec_hi arch.wc_sec_hi
+#endif
struct arch_shared_info arch;
@@ -698,24 +733,27 @@ typedef struct shared_info shared_info_t;
* 3. This the order of bootstrap elements in the initial virtual region:
* a. relocated kernel image
* b. initial ram disk [mod_start, mod_len]
+ * (may be omitted)
* c. list of allocated page frames [mfn_list, nr_pages]
* (unless relocated due to XEN_ELFNOTE_INIT_P2M)
* d. start_info_t structure [register ESI (x86)]
- * e. bootstrap page tables [pt_base and CR3 (x86)]
- * f. bootstrap stack [register ESP (x86)]
+ * in case of dom0 this page contains the console info, too
+ * e. unless dom0: xenstore ring page
+ * f. unless dom0: console ring page
+ * g. bootstrap page tables [pt_base and CR3 (x86)]
+ * h. bootstrap stack [register ESP (x86)]
* 4. Bootstrap elements are packed together, but each is 4kB-aligned.
- * 5. The initial ram disk may be omitted.
- * 6. The list of page frames forms a contiguous 'pseudo-physical' memory
+ * 5. The list of page frames forms a contiguous 'pseudo-physical' memory
* layout for the domain. In particular, the bootstrap virtual-memory
* region is a 1:1 mapping to the first section of the pseudo-physical map.
- * 7. All bootstrap elements are mapped read-writable for the guest OS. The
+ * 6. All bootstrap elements are mapped read-writable for the guest OS. The
* only exception is the bootstrap page table, which is mapped read-only.
- * 8. There is guaranteed to be at least 512kB padding after the final
+ * 7. There is guaranteed to be at least 512kB padding after the final
* bootstrap element. If necessary, the bootstrap virtual region is
* extended by an extra 4MB to ensure this.
*
* Note: Prior to 25833:bb85bbccb1c9. ("x86/32-on-64 adjust Dom0 initial page
- * table layout") a bug caused the pt_base (3.e above) and cr3 to not point
+ * table layout") a bug caused the pt_base (3.g above) and cr3 to not point
* to the start of the guest page tables (it was offset by two pages).
* This only manifested itself on 32-on-64 dom0 kernels and not 32-on-64 domU
* or 64-bit kernels of any colour. The page tables for a 32-on-64 dom0 got
@@ -759,6 +797,29 @@ struct start_info {
};
typedef struct start_info start_info_t;
+/*
+ * Start of day structure passed to PVH guests in %ebx.
+ *
+ * NOTE: nothing will be loaded at physical address 0, so
+ * a 0 value in any of the address fields should be treated
+ * as not present.
+ */
+struct hvm_start_info {
+#define HVM_START_MAGIC_VALUE 0x336ec578
+ uint32_t magic; /* Contains the magic value 0x336ec578 */
+ /* ("xEn3" with the 0x80 bit of the "E" set).*/
+ uint32_t flags; /* SIF_xxx flags. */
+ uint32_t cmdline_paddr; /* Physical address of the command line. */
+ uint32_t nr_modules; /* Number of modules passed to the kernel. */
+ uint32_t modlist_paddr; /* Physical address of an array of */
+ /* hvm_modlist_entry. */
+};
+
+struct hvm_modlist_entry {
+ uint32_t paddr; /* Physical address of the module. */
+ uint32_t size; /* Size of the module in bytes. */
+};
+
/* New console union for dom0 introduced in 0x00030203. */
#if __XEN_INTERFACE_VERSION__ < 0x00030203
#define console_mfn console.domU.mfn
@@ -771,6 +832,8 @@ typedef struct start_info start_info_t;
#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
#define SIF_MULTIBOOT_MOD (1<<2) /* Is mod_start a multiboot module? */
#define SIF_MOD_START_PFN (1<<3) /* Is mod_start a PFN? */
+#define SIF_VIRT_P2M_4TOOLS (1<<4) /* Do Xen tools understand a virt. mapped */
+ /* P->M making the 3 level tree obsolete? */
#define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */
/*
@@ -851,25 +914,19 @@ typedef struct dom0_vga_console_info {
typedef uint8_t xen_domain_handle_t[16];
-/* Turn a plain number into a C unsigned long constant. */
-#define __mk_unsigned_long(x) x ## UL
-#define mk_unsigned_long(x) __mk_unsigned_long(x)
-
__DEFINE_XEN_GUEST_HANDLE(uint8, uint8_t);
__DEFINE_XEN_GUEST_HANDLE(uint16, uint16_t);
__DEFINE_XEN_GUEST_HANDLE(uint32, uint32_t);
__DEFINE_XEN_GUEST_HANDLE(uint64, uint64_t);
-#else /* __ASSEMBLY__ */
-
-/* In assembly code we cannot use C numeric constant suffixes. */
-#define mk_unsigned_long(x) x
-
#endif /* !__ASSEMBLY__ */
/* Default definitions for macros used by domctl/sysctl. */
#if defined(__XEN__) || defined(__XEN_TOOLS__)
+#ifndef int64_aligned_t
+#define int64_aligned_t int64_t
+#endif
#ifndef uint64_aligned_t
#define uint64_aligned_t uint64_t
#endif
--
2.6.6

View File

@ -0,0 +1,212 @@
From e7afb8d41e024a88bfc78f4ee579e7c5dbd39616 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:11 +0100
Subject: [PATCH 06/11] xen: factor out p2m list allocation into separate
function
Do the p2m list allocation of the to be loaded kernel in a separate
function. This will allow doing the p2m list allocation at different
times of the boot preparations depending on the features the kernel
is supporting.
While at this remove superfluous setting of first_p2m_pfn and
nr_p2m_frames as those are needed only in case of the p2m list not
being mapped by the initial kernel mapping.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 89 ++++++++++++++++++++++++++-------------------
1 file changed, 51 insertions(+), 38 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index 691c22e..a2fd1f6 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -44,8 +44,10 @@ GRUB_MOD_LICENSE ("GPLv3+");
struct xen_loader_state {
struct grub_relocator *relocator;
+ struct grub_relocator_xen_state state;
struct start_info next_start;
struct grub_xen_file_info xen_inf;
+ grub_xen_mfn_t *virt_mfn_list;
grub_uint64_t max_addr;
struct xen_multiboot_mod_list *module_info_page;
grub_uint64_t modules_target_start;
@@ -170,7 +172,7 @@ generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
}
static grub_err_t
-set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
+set_mfns (grub_xen_mfn_t pfn)
{
grub_xen_mfn_t i, t;
grub_xen_mfn_t cn_pfn = -1, st_pfn = -1;
@@ -179,32 +181,34 @@ set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
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)
+ if (xen_state.virt_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)
+ if (xen_state.virt_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;
+ t = xen_state.virt_mfn_list[pfn];
+ xen_state.virt_mfn_list[pfn] = xen_state.virt_mfn_list[cn_pfn];
+ xen_state.virt_mfn_list[cn_pfn] = t;
+ t = xen_state.virt_mfn_list[pfn + 1];
+ xen_state.virt_mfn_list[pfn + 1] = xen_state.virt_mfn_list[st_pfn];
+ xen_state.virt_mfn_list[st_pfn] = t;
+
+ m2p_updates[0].ptr =
+ page2offset (xen_state.virt_mfn_list[pfn]) | MMU_MACHPHYS_UPDATE;
m2p_updates[0].val = pfn;
m2p_updates[1].ptr =
- page2offset (new_mfn_list[pfn + 1]) | MMU_MACHPHYS_UPDATE;
+ page2offset (xen_state.virt_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;
+ page2offset (xen_state.virt_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;
+ page2offset (xen_state.virt_mfn_list[st_pfn]) | MMU_MACHPHYS_UPDATE;
m2p_updates[3].val = st_pfn;
grub_xen_mmu_update (m2p_updates, 4, NULL, DOMID_SELF);
@@ -213,43 +217,52 @@ set_mfns (grub_xen_mfn_t * new_mfn_list, grub_xen_mfn_t pfn)
}
static grub_err_t
+grub_xen_p2m_alloc (void)
+{
+ grub_relocator_chunk_t ch;
+ grub_size_t p2msize;
+ grub_err_t err;
+
+ xen_state.state.mfn_list = xen_state.max_addr;
+ xen_state.next_start.mfn_list =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ p2msize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
+ err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
+ xen_state.max_addr, p2msize);
+ if (err)
+ return err;
+ xen_state.virt_mfn_list = get_virtual_current_address (ch);
+ grub_memcpy (xen_state.virt_mfn_list,
+ (void *) grub_xen_start_page_addr->mfn_list, p2msize);
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + p2msize, PAGE_SIZE);
+
+ 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 = xen_state.max_addr;
- xen_state.next_start.mfn_list =
- xen_state.max_addr + xen_state.xen_inf.virt_base;
- xen_state.next_start.first_p2m_pfn = xen_state.max_addr >> PAGE_SHIFT;
- pgtsize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
- err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
- xen_state.max_addr, pgtsize);
- xen_state.next_start.nr_p2m_frames = (pgtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ err = grub_xen_p2m_alloc ();
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);
- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + pgtsize, PAGE_SIZE);
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
xen_state.max_addr,
sizeof (xen_state.next_start));
if (err)
return err;
- state.start_info = xen_state.max_addr + xen_state.xen_inf.virt_base;
+ xen_state.state.start_info = xen_state.max_addr + xen_state.xen_inf.virt_base;
nst = get_virtual_current_address (ch);
xen_state.max_addr =
ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), PAGE_SIZE);
@@ -262,14 +275,14 @@ grub_xen_boot (void)
xen_state.next_start.console.domU = grub_xen_start_page_addr->console.domU;
xen_state.next_start.shared_info = grub_xen_start_page_addr->shared_info;
- err = set_mfns (new_mfn_list, xen_state.max_addr >> PAGE_SHIFT);
+ err = set_mfns (xen_state.max_addr >> PAGE_SHIFT);
if (err)
return err;
xen_state.max_addr += 2 * PAGE_SIZE;
xen_state.next_start.pt_base =
xen_state.max_addr + xen_state.xen_inf.virt_base;
- state.paging_start = xen_state.max_addr >> PAGE_SHIFT;
+ xen_state.state.paging_start = xen_state.max_addr >> PAGE_SHIFT;
nr_info_pages = xen_state.max_addr >> PAGE_SHIFT;
nr_pages = nr_info_pages;
@@ -298,15 +311,15 @@ grub_xen_boot (void)
generate_page_table (get_virtual_current_address (ch),
xen_state.max_addr >> PAGE_SHIFT, nr_pages,
- xen_state.xen_inf.virt_base, new_mfn_list);
+ xen_state.xen_inf.virt_base, xen_state.virt_mfn_list);
xen_state.max_addr += page2offset (nr_pt_pages);
- state.stack = xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
- state.entry_point = xen_state.xen_inf.entry_point;
+ xen_state.state.stack =
+ xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
+ xen_state.state.entry_point = xen_state.xen_inf.entry_point;
- xen_state.next_start.nr_p2m_frames += nr_pt_pages;
xen_state.next_start.nr_pt_frames = nr_pt_pages;
- state.paging_size = nr_pt_pages;
+ xen_state.state.paging_size = nr_pt_pages;
*nst = xen_state.next_start;
@@ -318,7 +331,7 @@ grub_xen_boot (void)
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 (xen_state.relocator, state, nr_pages,
+ return grub_relocator_xen_boot (xen_state.relocator, xen_state.state, nr_pages,
xen_state.xen_inf.virt_base <
PAGE_SIZE ? page2offset (nr_pages) : 0,
nr_pages - 1,
--
2.6.6

View File

@ -0,0 +1,121 @@
From 7f6888bb015764b99d90892bc506ded98f6ed9fe Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:12 +0100
Subject: [PATCH 07/11] xen: factor out allocation of special pages into
separate function
Do the allocation of special pages (start info, console and xenbus
ring buffers) in a separate function. This will allow to do the
allocation at different times of the boot preparations depending on
the features the kernel is supporting.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 48 +++++++++++++++++++++++++++++----------------
1 file changed, 31 insertions(+), 17 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index a2fd1f6..a80c0f8 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -48,6 +48,8 @@ struct xen_loader_state {
struct start_info next_start;
struct grub_xen_file_info xen_inf;
grub_xen_mfn_t *virt_mfn_list;
+ struct start_info *virt_start_info;
+ grub_xen_mfn_t console_pfn;
grub_uint64_t max_addr;
struct xen_multiboot_mod_list *module_info_page;
grub_uint64_t modules_target_start;
@@ -240,22 +242,10 @@ grub_xen_p2m_alloc (void)
}
static grub_err_t
-grub_xen_boot (void)
+grub_xen_special_alloc (void)
{
grub_relocator_chunk_t ch;
grub_err_t err;
- 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_size_t i;
-
- if (grub_xen_n_allocated_shared_pages)
- return grub_error (GRUB_ERR_BUG, "active grants");
-
- err = grub_xen_p2m_alloc ();
- if (err)
- return err;
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
xen_state.max_addr,
@@ -263,9 +253,11 @@ grub_xen_boot (void)
if (err)
return err;
xen_state.state.start_info = xen_state.max_addr + xen_state.xen_inf.virt_base;
- nst = get_virtual_current_address (ch);
+ xen_state.virt_start_info = get_virtual_current_address (ch);
xen_state.max_addr =
ALIGN_UP (xen_state.max_addr + sizeof (xen_state.next_start), PAGE_SIZE);
+ xen_state.console_pfn = xen_state.max_addr >> PAGE_SHIFT;
+ xen_state.max_addr += 2 * PAGE_SIZE;
xen_state.next_start.nr_pages = grub_xen_start_page_addr->nr_pages;
grub_memcpy (xen_state.next_start.magic, grub_xen_start_page_addr->magic,
@@ -275,10 +267,28 @@ grub_xen_boot (void)
xen_state.next_start.console.domU = grub_xen_start_page_addr->console.domU;
xen_state.next_start.shared_info = grub_xen_start_page_addr->shared_info;
- err = set_mfns (xen_state.max_addr >> PAGE_SHIFT);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_xen_boot (void)
+{
+ grub_relocator_chunk_t ch;
+ grub_err_t err;
+ grub_uint64_t nr_info_pages;
+ grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
+ struct gnttab_set_version gnttab_setver;
+ grub_size_t i;
+
+ if (grub_xen_n_allocated_shared_pages)
+ return grub_error (GRUB_ERR_BUG, "active grants");
+
+ err = grub_xen_p2m_alloc ();
+ if (err)
+ return err;
+ err = grub_xen_special_alloc ();
if (err)
return err;
- xen_state.max_addr += 2 * PAGE_SIZE;
xen_state.next_start.pt_base =
xen_state.max_addr + xen_state.xen_inf.virt_base;
@@ -309,6 +319,10 @@ grub_xen_boot (void)
if (err)
return err;
+ err = set_mfns (xen_state.console_pfn);
+ if (err)
+ return err;
+
generate_page_table (get_virtual_current_address (ch),
xen_state.max_addr >> PAGE_SHIFT, nr_pages,
xen_state.xen_inf.virt_base, xen_state.virt_mfn_list);
@@ -321,7 +335,7 @@ grub_xen_boot (void)
xen_state.next_start.nr_pt_frames = nr_pt_pages;
xen_state.state.paging_size = nr_pt_pages;
- *nst = xen_state.next_start;
+ *xen_state.virt_start_info = xen_state.next_start;
grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
--
2.6.6

View File

@ -0,0 +1,176 @@
From e5cce22a4448d84c50ef30acdd1990ecee16f2c2 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:13 +0100
Subject: [PATCH 08/11] xen: factor out allocation of page tables into separate
function
Do the allocation of page tables in a separate function. This will
allow to do the allocation at different times of the boot preparations
depending on the features the kernel is supporting.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 85 ++++++++++++++++++++++++++++-----------------
1 file changed, 53 insertions(+), 32 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index a80c0f8..2e12763 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -51,6 +51,9 @@ struct xen_loader_state {
struct start_info *virt_start_info;
grub_xen_mfn_t console_pfn;
grub_uint64_t max_addr;
+ grub_uint64_t *virt_pgtable;
+ grub_uint64_t pgtbl_start;
+ grub_uint64_t pgtbl_end;
struct xen_multiboot_mod_list *module_info_page;
grub_uint64_t modules_target_start;
grub_size_t n_modules;
@@ -110,17 +113,17 @@ get_pgtable_size (grub_uint64_t total_pages, grub_uint64_t virt_base)
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)
+ grub_uint64_t paging_end, grub_uint64_t total_pages,
+ grub_uint64_t virt_base, grub_xen_mfn_t *mfn_list)
{
if (!virt_base)
- total_pages++;
+ paging_end++;
grub_uint64_t lx[NUMBER_OF_LEVELS], lxs[NUMBER_OF_LEVELS];
grub_uint64_t nlx, nls, sz = 0;
int l;
- nlx = total_pages;
+ nlx = paging_end;
nls = virt_base >> PAGE_SHIFT;
for (l = 0; l < NUMBER_OF_LEVELS; l++)
{
@@ -164,7 +167,7 @@ generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
if (pr)
pg += POINTERS_PER_PAGE;
- for (j = 0; j < total_pages; j++)
+ for (j = 0; j < paging_end; j++)
{
if (j >= paging_start && j < lp)
pg[j + lxs[0]] = page2offset (mfn_list[j]) | 5;
@@ -271,24 +274,12 @@ grub_xen_special_alloc (void)
}
static grub_err_t
-grub_xen_boot (void)
+grub_xen_pt_alloc (void)
{
grub_relocator_chunk_t ch;
grub_err_t err;
grub_uint64_t nr_info_pages;
grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
- struct gnttab_set_version gnttab_setver;
- grub_size_t i;
-
- if (grub_xen_n_allocated_shared_pages)
- return grub_error (GRUB_ERR_BUG, "active grants");
-
- err = grub_xen_p2m_alloc ();
- if (err)
- return err;
- err = grub_xen_special_alloc ();
- if (err)
- return err;
xen_state.next_start.pt_base =
xen_state.max_addr + xen_state.xen_inf.virt_base;
@@ -309,32 +300,62 @@ grub_xen_boot (void)
nr_pages = nr_need_pages;
}
- grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
- (unsigned long long) xen_state.xen_inf.virt_base,
- (unsigned long long) page2offset (nr_pages));
-
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
xen_state.max_addr,
page2offset (nr_pt_pages));
if (err)
return err;
+ xen_state.virt_pgtable = get_virtual_current_address (ch);
+ xen_state.pgtbl_start = xen_state.max_addr >> PAGE_SHIFT;
+ xen_state.max_addr += page2offset (nr_pt_pages);
+ xen_state.state.stack =
+ xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
+ xen_state.state.paging_size = nr_pt_pages;
+ xen_state.next_start.nr_pt_frames = nr_pt_pages;
+ xen_state.max_addr = page2offset (nr_pages);
+ xen_state.pgtbl_end = nr_pages;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_xen_boot (void)
+{
+ grub_err_t err;
+ grub_uint64_t nr_pages;
+ struct gnttab_set_version gnttab_setver;
+ grub_size_t i;
+
+ if (grub_xen_n_allocated_shared_pages)
+ return grub_error (GRUB_ERR_BUG, "active grants");
+
+ err = grub_xen_p2m_alloc ();
+ if (err)
+ return err;
+ err = grub_xen_special_alloc ();
+ if (err)
+ return err;
+ err = grub_xen_pt_alloc ();
+ if (err)
+ return err;
+
err = set_mfns (xen_state.console_pfn);
if (err)
return err;
- generate_page_table (get_virtual_current_address (ch),
- xen_state.max_addr >> PAGE_SHIFT, nr_pages,
+ nr_pages = xen_state.max_addr >> PAGE_SHIFT;
+
+ grub_dprintf ("xen", "bootstrap domain %llx+%llx\n",
+ (unsigned long long) xen_state.xen_inf.virt_base,
+ (unsigned long long) page2offset (nr_pages));
+
+ generate_page_table (xen_state.virt_pgtable, xen_state.pgtbl_start,
+ xen_state.pgtbl_end, nr_pages,
xen_state.xen_inf.virt_base, xen_state.virt_mfn_list);
- xen_state.max_addr += page2offset (nr_pt_pages);
- xen_state.state.stack =
- xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
xen_state.state.entry_point = xen_state.xen_inf.entry_point;
- xen_state.next_start.nr_pt_frames = nr_pt_pages;
- xen_state.state.paging_size = nr_pt_pages;
-
*xen_state.virt_start_info = xen_state.next_start;
grub_memset (&gnttab_setver, 0, sizeof (gnttab_setver));
@@ -348,8 +369,8 @@ grub_xen_boot (void)
return grub_relocator_xen_boot (xen_state.relocator, xen_state.state, nr_pages,
xen_state.xen_inf.virt_base <
PAGE_SIZE ? page2offset (nr_pages) : 0,
- nr_pages - 1,
- page2offset (nr_pages - 1) +
+ xen_state.pgtbl_end - 1,
+ page2offset (xen_state.pgtbl_end - 1) +
xen_state.xen_inf.virt_base);
}
--
2.6.6

View File

@ -0,0 +1,178 @@
From 9c7798d3bed807f29a7056bac5bd8c4b0f33ca34 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:14 +0100
Subject: [PATCH 09/11] xen: add capability to load initrd outside of initial
mapping
Modern pvops linux kernels support an initrd not covered by the initial
mapping. This capability is flagged by an elf-note.
In case the elf-note is set by the kernel don't place the initrd into
the initial mapping. This will allow to load larger initrds and/or
support domains with larger memory, as the initial mapping is limited
to 2GB and it is containing the p2m list.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 60 +++++++++++++++++++++++++++++++-------
grub-core/loader/i386/xen_fileXX.c | 3 ++
include/grub/xen_file.h | 1 +
3 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index 2e12763..9639ca1 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -228,6 +228,9 @@ grub_xen_p2m_alloc (void)
grub_size_t p2msize;
grub_err_t err;
+ if (xen_state.virt_mfn_list)
+ return GRUB_ERR_NONE;
+
xen_state.state.mfn_list = xen_state.max_addr;
xen_state.next_start.mfn_list =
xen_state.max_addr + xen_state.xen_inf.virt_base;
@@ -250,6 +253,9 @@ grub_xen_special_alloc (void)
grub_relocator_chunk_t ch;
grub_err_t err;
+ if (xen_state.virt_start_info)
+ return GRUB_ERR_NONE;
+
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
xen_state.max_addr,
sizeof (xen_state.next_start));
@@ -281,6 +287,9 @@ grub_xen_pt_alloc (void)
grub_uint64_t nr_info_pages;
grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
+ if (xen_state.virt_pgtable)
+ return GRUB_ERR_NONE;
+
xen_state.next_start.pt_base =
xen_state.max_addr + xen_state.xen_inf.virt_base;
xen_state.state.paging_start = xen_state.max_addr >> PAGE_SHIFT;
@@ -319,16 +328,11 @@ grub_xen_pt_alloc (void)
return GRUB_ERR_NONE;
}
+/* Allocate all not yet allocated areas mapped by initial page tables. */
static grub_err_t
-grub_xen_boot (void)
+grub_xen_alloc_boot_data (void)
{
grub_err_t err;
- grub_uint64_t nr_pages;
- struct gnttab_set_version gnttab_setver;
- grub_size_t i;
-
- if (grub_xen_n_allocated_shared_pages)
- return grub_error (GRUB_ERR_BUG, "active grants");
err = grub_xen_p2m_alloc ();
if (err)
@@ -340,6 +344,24 @@ grub_xen_boot (void)
if (err)
return err;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_xen_boot (void)
+{
+ grub_err_t err;
+ grub_uint64_t nr_pages;
+ struct gnttab_set_version gnttab_setver;
+ grub_size_t i;
+
+ if (grub_xen_n_allocated_shared_pages)
+ return grub_error (GRUB_ERR_BUG, "active grants");
+
+ err = grub_xen_alloc_boot_data ();
+ if (err)
+ return err;
+
err = set_mfns (xen_state.console_pfn);
if (err)
return err;
@@ -610,6 +632,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
+ if (xen_state.xen_inf.unmapped_initrd)
+ {
+ err = grub_xen_alloc_boot_data ();
+ if (err)
+ goto fail;
+ }
+
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
@@ -627,14 +656,22 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- xen_state.next_start.mod_start =
- xen_state.max_addr + xen_state.xen_inf.virt_base;
xen_state.next_start.mod_len = size;
- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE);
+ if (xen_state.xen_inf.unmapped_initrd)
+ {
+ xen_state.next_start.flags |= SIF_MOD_START_PFN;
+ xen_state.next_start.mod_start = xen_state.max_addr >> PAGE_SHIFT;
+ }
+ else
+ xen_state.next_start.mod_start =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
grub_dprintf ("xen", "Initrd, addr=0x%x, size=0x%x\n",
- (unsigned) xen_state.next_start.mod_start, (unsigned) size);
+ (unsigned) (xen_state.max_addr + xen_state.xen_inf.virt_base),
+ (unsigned) size);
+
+ xen_state.max_addr = ALIGN_UP (xen_state.max_addr + size, PAGE_SIZE);
fail:
grub_initrd_close (&initrd_ctx);
@@ -686,6 +723,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
if (!xen_state.module_info_page)
{
+ xen_state.xen_inf.unmapped_initrd = 0;
xen_state.n_modules = 0;
xen_state.max_addr = ALIGN_UP (xen_state.max_addr, PAGE_SIZE);
xen_state.modules_target_start = xen_state.max_addr;
diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
index 03215ca..8751174 100644
--- a/grub-core/loader/i386/xen_fileXX.c
+++ b/grub-core/loader/i386/xen_fileXX.c
@@ -261,6 +261,9 @@ parse_note (grub_elf_t elf, struct grub_xen_file_info *xi,
descsz == 2 ? 2 : 3) == 0)
xi->arch = GRUB_XEN_FILE_I386;
break;
+ case XEN_ELFNOTE_MOD_START_PFN:
+ xi->unmapped_initrd = !!grub_le_to_cpu32(*(grub_uint32_t *) desc);
+ break;
default:
grub_dprintf ("xen", "unknown note type %d\n", nh->n_type);
break;
diff --git a/include/grub/xen_file.h b/include/grub/xen_file.h
index 4b2ccba..ed749fa 100644
--- a/include/grub/xen_file.h
+++ b/include/grub/xen_file.h
@@ -36,6 +36,7 @@ struct grub_xen_file_info
int has_note;
int has_xen_guest;
int extended_cr3;
+ int unmapped_initrd;
enum
{
GRUB_XEN_FILE_I386 = 1,
--
2.6.6

View File

@ -0,0 +1,951 @@
From de018561ca5b1d5fd0d187be0d03d93da3ef4501 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:15 +0100
Subject: [PATCH 10/11] xen: modify page table construction
Modify the page table construction to allow multiple virtual regions
to be mapped. This is done as preparation for removing the p2m list
from the initial kernel mapping in order to support huge pv domains.
This allows a cleaner approach for mapping the relocator page by
using this capability.
The interface to the assembler level of the relocator has to be changed
in order to be able to process multiple page table areas.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/i386/xen/relocator.S | 89 ++++++----
grub-core/lib/x86_64/xen/relocator.S | 136 ++++++---------
grub-core/lib/xen/relocator.c | 28 ++-
grub-core/loader/i386/xen.c | 323 +++++++++++++++++++++++------------
include/grub/i386/memory.h | 7 +
include/grub/xen/relocator.h | 6 +-
6 files changed, 357 insertions(+), 232 deletions(-)
diff --git a/grub-core/lib/i386/xen/relocator.S b/grub-core/lib/i386/xen/relocator.S
index 694a54c..f1c729e 100644
--- a/grub-core/lib/i386/xen/relocator.S
+++ b/grub-core/lib/i386/xen/relocator.S
@@ -16,6 +16,8 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <grub/i386/memory.h>
+#include <grub/i386/types.h>
#include <grub/symbol.h>
#include <grub/xen.h>
@@ -23,78 +25,86 @@
VARIABLE(grub_relocator_xen_remap_start)
LOCAL(base):
- /* mov imm32, %ebx */
+ /* Remap the remapper to it's new address. */
+ /* mov imm32, %ebx - %ebx: new virtual address of remapper */
.byte 0xbb
VARIABLE(grub_relocator_xen_remapper_virt)
.long 0
- /* mov imm32, %ecx */
+ /* mov imm32, %ecx - %ecx: low part of page table entry */
.byte 0xb9
VARIABLE(grub_relocator_xen_remapper_map)
.long 0
- /* mov imm32, %edx */
+ /* mov imm32, %edx - %edx: high part of page table entry */
.byte 0xba
VARIABLE(grub_relocator_xen_remapper_map_high)
.long 0
- movl %ebx, %ebp
+ movl %ebx, %ebp /* %ebx is clobbered by hypercall */
- movl $2, %esi
+ movl $UVMF_INVLPG, %esi /* esi: flags (inv. single entry) */
movl $__HYPERVISOR_update_va_mapping, %eax
int $0x82
movl %ebp, %ebx
addl $(LOCAL(cont) - LOCAL(base)), %ebx
- jmp *%ebx
+ jmp *%ebx /* Continue with new virtual address */
LOCAL(cont):
- xorl %eax, %eax
- movl %eax, %ebp
+ /* Modify mappings of new page tables to be read-only. */
+ /* mov imm32, %eax */
+ .byte 0xb8
+VARIABLE(grub_relocator_xen_paging_areas_addr)
+ .long 0
+ movl %eax, %ebx
1:
-
+ movl 0(%ebx), %ebp /* Get start pfn of the current area */
+ movl GRUB_TARGET_SIZEOF_LONG(%ebx), %ecx /* Get # of pg tables */
+ testl %ecx, %ecx /* 0 -> last area reached */
+ jz 3f
+ addl $(2 * GRUB_TARGET_SIZEOF_LONG), %ebx
+ movl %ebx, %esp /* Save current area pointer */
+
+2:
+ movl %ecx, %edi
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator_xen_mfn_list)
.long 0
- movl %eax, %edi
- movl %ebp, %eax
- movl 0(%edi, %eax, 4), %ecx
-
- /* mov imm32, %ebx */
- .byte 0xbb
-VARIABLE(grub_relocator_xen_paging_start)
- .long 0
- shll $12, %eax
- addl %eax, %ebx
+ movl 0(%eax, %ebp, 4), %ecx /* mfn */
+ movl %ebp, %ebx
+ shll $PAGE_SHIFT, %ebx /* virtual address (1:1 mapping) */
movl %ecx, %edx
- shll $12, %ecx
- shrl $20, %edx
- orl $5, %ecx
- movl $2, %esi
+ shll $PAGE_SHIFT, %ecx /* prepare pte low part */
+ shrl $(32 - PAGE_SHIFT), %edx /* pte high part */
+ orl $(GRUB_PAGE_PRESENT | GRUB_PAGE_USER), %ecx /* pte low */
+ movl $UVMF_INVLPG, %esi
movl $__HYPERVISOR_update_va_mapping, %eax
- int $0x82
+ int $0x82 /* parameters: eax, ebx, ecx, edx, esi */
- incl %ebp
- /* mov imm32, %ecx */
- .byte 0xb9
-VARIABLE(grub_relocator_xen_paging_size)
- .long 0
- cmpl %ebp, %ecx
+ incl %ebp /* next pfn */
+ movl %edi, %ecx
+
+ loop 2b
- ja 1b
+ mov %esp, %ebx /* restore area poniter */
+ jmp 1b
+3:
+ /* Switch page tables: pin new L3 pt, load cr3, unpin old L3. */
/* mov imm32, %ebx */
.byte 0xbb
VARIABLE(grub_relocator_xen_mmu_op_addr)
.long 0
- movl $3, %ecx
- movl $0, %edx
- movl $0x7FF0, %esi
+ movl $3, %ecx /* 3 mmu ops */
+ movl $0, %edx /* pdone (not used) */
+ movl $DOMID_SELF, %esi
movl $__HYPERVISOR_mmuext_op, %eax
int $0x82
+ /* Continue in virtual kernel mapping. */
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator_xen_remap_continue)
@@ -102,6 +112,9 @@ VARIABLE(grub_relocator_xen_remap_continue)
jmp *%eax
+VARIABLE(grub_relocator_xen_paging_areas)
+ .long 0, 0, 0, 0, 0, 0, 0, 0
+
VARIABLE(grub_relocator_xen_mmu_op)
.space 256
@@ -109,6 +122,7 @@ VARIABLE(grub_relocator_xen_remap_end)
VARIABLE(grub_relocator_xen_start)
+ /* Unmap old remapper area. */
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator_xen_remapper_virt2)
@@ -116,14 +130,14 @@ VARIABLE(grub_relocator_xen_remapper_virt2)
movl %eax, %edi
- xorl %ecx, %ecx
+ xorl %ecx, %ecx /* Invalid pte */
xorl %edx, %edx
- movl $2, %esi
+ movl $UVMF_INVLPG, %esi
movl $__HYPERVISOR_update_va_mapping, %eax
int $0x82
-
+ /* Prepare registers for starting kernel. */
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator_xen_stack)
@@ -145,6 +159,7 @@ VARIABLE(grub_relocator_xen_start_info)
VARIABLE(grub_relocator_xen_entry_point)
.long 0
+ /* Now start the new kernel. */
jmp *%eax
VARIABLE(grub_relocator_xen_end)
diff --git a/grub-core/lib/x86_64/xen/relocator.S b/grub-core/lib/x86_64/xen/relocator.S
index 92e9e72..f5364ed 100644
--- a/grub-core/lib/x86_64/xen/relocator.S
+++ b/grub-core/lib/x86_64/xen/relocator.S
@@ -16,95 +16,85 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <grub/x86_64/memory.h>
+#include <grub/x86_64/types.h>
#include <grub/symbol.h>
#include <grub/xen.h>
+/* Macro to load an imm64 value stored by the C-part into %rax: */
+#define MOV_IMM64_RAX(var) .byte 0x48, 0xb8; VARIABLE(var); .quad 0
+
.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
+ /* Remap the remapper to it's new address. */
+ MOV_IMM64_RAX(grub_relocator_xen_remapper_virt)
- movq %rax, %rdi
- movq %rax, %rbx
+ movq %rax, %rdi /* %rdi: new virtual address of remapper */
+ movq %rax, %rbx /* Remember new virtual address */
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_remapper_map)
- .quad 0
+ MOV_IMM64_RAX(grub_relocator_xen_remapper_map)
- movq %rax, %rsi
+ movq %rax, %rsi /* %rsi: page table entry */
- movq $2, %rdx
+ movq $UVMF_INVLPG, %rdx /* %rdx: flags (inv. single entry) */
movq $__HYPERVISOR_update_va_mapping, %rax
- syscall
+ syscall /* Do the remap operation */
addq $(LOCAL(cont) - LOCAL(base)), %rbx
- jmp *%rbx
+ jmp *%rbx /* Continue with new virtual address */
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, %r12
-
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_mfn_list)
- .quad 0
+ /* Modify mappings of new page tables to be read-only. */
+ MOV_IMM64_RAX(grub_relocator_xen_mfn_list)
+
+ movq %rax, %rbx /* %rbx is the base of the p2m list */
+ leaq EXT_C(grub_relocator_xen_paging_areas) (%rip), %r8
- movq %rax, %rsi
1:
+ movq 0(%r8), %r12 /* Get start pfn of the current area */
+ movq GRUB_TARGET_SIZEOF_LONG(%r8), %rcx /* Get # of pg tables */
+ testq %rcx, %rcx /* 0 -> last area reached */
+ jz 3f
+2:
movq %r12, %rdi
- movq %rsi, %rbx
- movq 0(%rsi), %rsi
- shlq $12, %rsi
- orq $5, %rsi
- movq $2, %rdx
- movq %rcx, %r9
+ shlq $PAGE_SHIFT, %rdi /* virtual address (1:1 mapping) */
+ movq (%rbx, %r12, 8), %rsi /* mfn */
+ shlq $PAGE_SHIFT, %rsi
+ orq $(GRUB_PAGE_PRESENT | GRUB_PAGE_USER), %rsi /* Build pte */
+ movq $UVMF_INVLPG, %rdx
+ movq %rcx, %r9 /* %rcx clobbered by hypercall */
movq $__HYPERVISOR_update_va_mapping, %rax
syscall
movq %r9, %rcx
- addq $8, %rbx
- addq $4096, %r12
- movq %rbx, %rsi
+ incq %r12 /* next pfn */
+
+ loop 2b
- loop 1b
+ addq $(2 * GRUB_TARGET_SIZEOF_LONG), %r8 /* next pg table area */
+ jmp 1b
- leaq LOCAL(mmu_op) (%rip), %rdi
- movq $3, %rsi
- movq $0, %rdx
- movq $0x7FF0, %r10
+3:
+ /* Switch page tables: pin new L4 pt, load cr3, unpin old L4. */
+ leaq EXT_C(grub_relocator_xen_mmu_op) (%rip), %rdi
+ movq $3, %rsi /* 3 mmu ops */
+ movq $0, %rdx /* pdone (not used) */
+ movq $DOMID_SELF, %r10
movq $__HYPERVISOR_mmuext_op, %rax
syscall
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_remap_continue)
- .quad 0
+ /* Continue in virtual kernel mapping. */
+ MOV_IMM64_RAX(grub_relocator_xen_remap_continue)
jmp *%rax
-LOCAL(mmu_op):
+VARIABLE(grub_relocator_xen_paging_areas)
+ /* array of start, size pairs, size 0 is end marker */
+ .quad 0, 0, 0, 0, 0, 0, 0, 0
+
VARIABLE(grub_relocator_xen_mmu_op)
.space 256
@@ -112,46 +102,32 @@ 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
+ /* Unmap old remapper area. */
+ MOV_IMM64_RAX(grub_relocator_xen_remapper_virt2)
movq %rax, %rdi
- xorq %rax, %rax
+ xorq %rax, %rax /* Invalid pte */
movq %rax, %rsi
- movq $2, %rdx
+ movq $UVMF_INVLPG, %rdx
movq $__HYPERVISOR_update_va_mapping, %rax
syscall
-
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_stack)
- .quad 0
+ /* Prepare registers for starting kernel. */
+ MOV_IMM64_RAX(grub_relocator_xen_stack)
movq %rax, %rsp
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_start_info)
- .quad 0
+ MOV_IMM64_RAX(grub_relocator_xen_start_info)
movq %rax, %rsi
cld
- /* mov imm64, %rax */
- .byte 0x48
- .byte 0xb8
-VARIABLE(grub_relocator_xen_entry_point)
- .quad 0
+ MOV_IMM64_RAX(grub_relocator_xen_entry_point)
+ /* Now start the new kernel. */
jmp *%rax
VARIABLE(grub_relocator_xen_end)
diff --git a/grub-core/lib/xen/relocator.c b/grub-core/lib/xen/relocator.c
index 8f427d3..4d0cbca 100644
--- a/grub-core/lib/xen/relocator.c
+++ b/grub-core/lib/xen/relocator.c
@@ -29,6 +29,11 @@
typedef grub_addr_t grub_xen_reg_t;
+struct grub_relocator_xen_paging_area {
+ grub_xen_reg_t start;
+ grub_xen_reg_t size;
+} GRUB_PACKED;
+
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;
@@ -36,15 +41,16 @@ 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 struct grub_relocator_xen_paging_area
+ grub_relocator_xen_paging_areas[XEN_MAX_MAPPINGS];
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_paging_areas_addr;
extern grub_xen_reg_t grub_relocator_xen_remapper_map_high;
#endif
extern mmuext_op_t grub_relocator_xen_mmu_op[3];
@@ -61,6 +67,7 @@ grub_relocator_xen_boot (struct grub_relocator *rel,
{
grub_err_t err;
void *relst;
+ int i;
grub_relocator_chunk_t ch, ch_tramp;
grub_xen_mfn_t *mfn_list =
(grub_xen_mfn_t *) grub_xen_start_page_addr->mfn_list;
@@ -77,8 +84,11 @@ grub_relocator_xen_boot (struct grub_relocator *rel,
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;
+ for (i = 0; i < XEN_MAX_MAPPINGS; i++)
+ {
+ grub_relocator_xen_paging_areas[i].start = state.paging_start[i];
+ grub_relocator_xen_paging_areas[i].size = state.paging_size[i];
+ }
grub_relocator_xen_remapper_virt = remapper_virt;
grub_relocator_xen_remapper_virt2 = remapper_virt;
grub_relocator_xen_remap_continue = trampoline_virt;
@@ -88,10 +98,12 @@ grub_relocator_xen_boot (struct grub_relocator *rel,
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;
+ grub_relocator_xen_paging_areas_addr =
+ (char *) &grub_relocator_xen_paging_areas
+ - (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_relocator_xen_mfn_list = state.mfn_list;
grub_memset (grub_relocator_xen_mmu_op, 0,
sizeof (grub_relocator_xen_mmu_op));
@@ -100,9 +112,9 @@ grub_relocator_xen_boot (struct grub_relocator *rel,
#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[0].arg1.mfn = mfn_list[state.paging_start[0]];
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[1].arg1.mfn = mfn_list[state.paging_start[0]];
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];
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index 9639ca1..a98badf 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -39,9 +39,34 @@
#include <grub/xen.h>
#include <grub/xen_file.h>
#include <grub/linux.h>
+#include <grub/i386/memory.h>
GRUB_MOD_LICENSE ("GPLv3+");
+#ifdef __x86_64__
+#define NUMBER_OF_LEVELS 4
+#define INTERMEDIATE_OR (GRUB_PAGE_PRESENT | GRUB_PAGE_RW | GRUB_PAGE_USER)
+#define VIRT_MASK 0x0000ffffffffffffULL
+#else
+#define NUMBER_OF_LEVELS 3
+#define INTERMEDIATE_OR (GRUB_PAGE_PRESENT | GRUB_PAGE_RW)
+#define VIRT_MASK 0x00000000ffffffffULL
+#define HYPERVISOR_PUD_ADDRESS 0xc0000000ULL
+#endif
+
+struct grub_xen_mapping_lvl {
+ grub_uint64_t virt_start;
+ grub_uint64_t virt_end;
+ grub_uint64_t pfn_start;
+ grub_uint64_t n_pt_pages;
+};
+
+struct grub_xen_mapping {
+ grub_uint64_t *where;
+ struct grub_xen_mapping_lvl area;
+ struct grub_xen_mapping_lvl lvls[NUMBER_OF_LEVELS];
+};
+
struct xen_loader_state {
struct grub_relocator *relocator;
struct grub_relocator_xen_state state;
@@ -51,12 +76,13 @@ struct xen_loader_state {
struct start_info *virt_start_info;
grub_xen_mfn_t console_pfn;
grub_uint64_t max_addr;
- grub_uint64_t *virt_pgtable;
- grub_uint64_t pgtbl_start;
grub_uint64_t pgtbl_end;
struct xen_multiboot_mod_list *module_info_page;
grub_uint64_t modules_target_start;
grub_size_t n_modules;
+ struct grub_xen_mapping *map_reloc;
+ struct grub_xen_mapping mappings[XEN_MAX_MAPPINGS];
+ int n_mappings;
int loaded;
};
@@ -64,9 +90,8 @@ static struct xen_loader_state xen_state;
static grub_dl_t my_mod;
-#define PAGE_SIZE 4096
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
#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)
@@ -79,100 +104,163 @@ 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)
+static grub_err_t
+get_pgtable_size (grub_uint64_t from, grub_uint64_t to, grub_uint64_t pfn)
{
- 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;
-}
+ struct grub_xen_mapping *map, *map_cmp;
+ grub_uint64_t mask, bits;
+ int i, m;
-static void
-generate_page_table (grub_uint64_t *where, grub_uint64_t paging_start,
- grub_uint64_t paging_end, grub_uint64_t total_pages,
- grub_uint64_t virt_base, grub_xen_mfn_t *mfn_list)
-{
- if (!virt_base)
- paging_end++;
+ if (xen_state.n_mappings == XEN_MAX_MAPPINGS)
+ return grub_error (GRUB_ERR_BUG, "too many mapped areas");
- grub_uint64_t lx[NUMBER_OF_LEVELS], lxs[NUMBER_OF_LEVELS];
- grub_uint64_t nlx, nls, sz = 0;
- int l;
+ grub_dprintf ("xen", "get_pgtable_size %d from=%llx, to=%llx, pfn=%llx\n",
+ xen_state.n_mappings, (unsigned long long) from,
+ (unsigned long long) to, (unsigned long long) pfn);
- nlx = paging_end;
- nls = virt_base >> PAGE_SHIFT;
- for (l = 0; l < NUMBER_OF_LEVELS; l++)
+ map = xen_state.mappings + xen_state.n_mappings;
+ grub_memset (map, 0, sizeof (*map));
+
+ map->area.virt_start = from & VIRT_MASK;
+ map->area.virt_end = (to - 1) & VIRT_MASK;
+ map->area.n_pt_pages = 0;
+
+ for (i = NUMBER_OF_LEVELS - 1; i >= 0; i--)
{
- nlx = (nlx + POINTERS_PER_PAGE - 1) >> LOG_POINTERS_PER_PAGE;
- /* PAE wants all 4 root directories present. */
+ map->lvls[i].pfn_start = pfn + map->area.n_pt_pages;
+ if (i == NUMBER_OF_LEVELS - 1)
+ {
+ if (xen_state.n_mappings == 0)
+ {
+ map->lvls[i].virt_start = 0;
+ map->lvls[i].virt_end = VIRT_MASK;
+ map->lvls[i].n_pt_pages = 1;
+ map->area.n_pt_pages++;
+ }
+ continue;
+ }
+
+ bits = PAGE_SHIFT + (i + 1) * LOG_POINTERS_PER_PAGE;
+ mask = (1ULL << bits) - 1;
+ map->lvls[i].virt_start = map->area.virt_start & ~mask;
+ map->lvls[i].virt_end = map->area.virt_end | mask;
#ifdef __i386__
- if (l == 1)
- nlx = 4;
+ /* PAE wants last root directory present. */
+ if (i == 1 && to <= HYPERVISOR_PUD_ADDRESS && xen_state.n_mappings == 0)
+ map->lvls[i].virt_end = VIRT_MASK;
#endif
- lx[l] = nlx;
- sz += lx[l];
- lxs[l] = nls & (POINTERS_PER_PAGE - 1);
- if (nls && l != 0)
- sz++;
- nls >>= LOG_POINTERS_PER_PAGE;
+ for (m = 0; m < xen_state.n_mappings; m++)
+ {
+ map_cmp = xen_state.mappings + m;
+ if (map_cmp->lvls[i].virt_start == map_cmp->lvls[i].virt_end)
+ continue;
+ if (map->lvls[i].virt_start >= map_cmp->lvls[i].virt_start &&
+ map->lvls[i].virt_end <= map_cmp->lvls[i].virt_end)
+ {
+ map->lvls[i].virt_start = 0;
+ map->lvls[i].virt_end = 0;
+ break;
+ }
+ if (map->lvls[i].virt_start >= map_cmp->lvls[i].virt_start &&
+ map->lvls[i].virt_start <= map_cmp->lvls[i].virt_end)
+ map->lvls[i].virt_start = map_cmp->lvls[i].virt_end + 1;
+ if (map->lvls[i].virt_end >= map_cmp->lvls[i].virt_start &&
+ map->lvls[i].virt_end <= map_cmp->lvls[i].virt_end)
+ map->lvls[i].virt_end = map_cmp->lvls[i].virt_start - 1;
+ }
+ if (map->lvls[i].virt_start < map->lvls[i].virt_end)
+ map->lvls[i].n_pt_pages =
+ ((map->lvls[i].virt_end - map->lvls[i].virt_start) >> bits) + 1;
+ map->area.n_pt_pages += map->lvls[i].n_pt_pages;
+ grub_dprintf ("xen", "get_pgtable_size level %d: virt %llx-%llx %d pts\n",
+ i, (unsigned long long) map->lvls[i].virt_start,
+ (unsigned long long) map->lvls[i].virt_end,
+ (int) map->lvls[i].n_pt_pages);
}
- grub_uint64_t lp;
- grub_uint64_t j;
- grub_uint64_t *pg = (grub_uint64_t *) where;
- int pr = 0;
+ grub_dprintf ("xen", "get_pgtable_size return: %d page tables\n",
+ (int) map->area.n_pt_pages);
- grub_memset (pg, 0, sz * PAGE_SIZE);
+ xen_state.state.paging_start[xen_state.n_mappings] = pfn;
+ xen_state.state.paging_size[xen_state.n_mappings] = map->area.n_pt_pages;
- lp = paging_start + lx[NUMBER_OF_LEVELS - 1];
- for (l = NUMBER_OF_LEVELS - 1; l >= 1; l--)
+ return GRUB_ERR_NONE;
+}
+
+static grub_uint64_t *
+get_pg_table_virt (int mapping, int level)
+{
+ grub_uint64_t pfn;
+ struct grub_xen_mapping *map;
+
+ map = xen_state.mappings + mapping;
+ pfn = map->lvls[level].pfn_start - map->lvls[NUMBER_OF_LEVELS - 1].pfn_start;
+ return map->where + pfn * POINTERS_PER_PAGE;
+}
+
+static grub_uint64_t
+get_pg_table_prot (int level, grub_uint64_t pfn)
+{
+ int m;
+ grub_uint64_t pfn_s, pfn_e;
+
+ if (level > 0)
+ return INTERMEDIATE_OR;
+ for (m = 0; m < xen_state.n_mappings; m++)
{
- 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;
+ pfn_s = xen_state.mappings[m].lvls[NUMBER_OF_LEVELS - 1].pfn_start;
+ pfn_e = xen_state.mappings[m].area.n_pt_pages + pfn_s;
+ if (pfn >= pfn_s && pfn < pfn_e)
+ return GRUB_PAGE_PRESENT | GRUB_PAGE_USER;
}
+ return GRUB_PAGE_PRESENT | GRUB_PAGE_RW | GRUB_PAGE_USER;
+}
+
+static void
+generate_page_table (grub_xen_mfn_t *mfn_list)
+{
+ int l, m1, m2;
+ long p, p_s, p_e;
+ grub_uint64_t start, end, pfn;
+ grub_uint64_t *pg;
+ struct grub_xen_mapping_lvl *lvl;
- if (lxs[0] || pr)
- pg[0] = page2offset (mfn_list[total_pages]) | 5;
- if (pr)
- pg += POINTERS_PER_PAGE;
+ for (m1 = 0; m1 < xen_state.n_mappings; m1++)
+ grub_memset (xen_state.mappings[m1].where, 0,
+ xen_state.mappings[m1].area.n_pt_pages * PAGE_SIZE);
- for (j = 0; j < paging_end; j++)
+ for (l = NUMBER_OF_LEVELS - 1; l >= 0; l--)
{
- 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;
+ for (m1 = 0; m1 < xen_state.n_mappings; m1++)
+ {
+ start = xen_state.mappings[m1].lvls[l].virt_start;
+ end = xen_state.mappings[m1].lvls[l].virt_end;
+ pg = get_pg_table_virt(m1, l);
+ for (m2 = 0; m2 < xen_state.n_mappings; m2++)
+ {
+ lvl = (l > 0) ? xen_state.mappings[m2].lvls + l - 1
+ : &xen_state.mappings[m2].area;
+ if (l > 0 && lvl->n_pt_pages == 0)
+ continue;
+ if (lvl->virt_start >= end || lvl->virt_end <= start)
+ continue;
+ p_s = (grub_max (start, lvl->virt_start) - start) >>
+ (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE);
+ p_e = (grub_min (end, lvl->virt_end) - start) >>
+ (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE);
+ pfn = ((grub_max (start, lvl->virt_start) - lvl->virt_start) >>
+ (PAGE_SHIFT + l * LOG_POINTERS_PER_PAGE)) + lvl->pfn_start;
+ grub_dprintf ("xen", "write page table entries level %d pg %p "
+ "mapping %d/%d index %lx-%lx pfn %llx\n",
+ l, pg, m1, m2, p_s, p_e, (unsigned long long) pfn);
+ for (p = p_s; p <= p_e; p++)
+ {
+ pg[p] = page2offset (mfn_list[pfn]) |
+ get_pg_table_prot (l, pfn);
+ pfn++;
+ }
+ }
+ }
}
}
@@ -285,45 +373,71 @@ grub_xen_pt_alloc (void)
grub_relocator_chunk_t ch;
grub_err_t err;
grub_uint64_t nr_info_pages;
- grub_uint64_t nr_pages, nr_pt_pages, nr_need_pages;
+ grub_uint64_t nr_need_pages;
+ grub_uint64_t try_virt_end;
+ struct grub_xen_mapping *map;
- if (xen_state.virt_pgtable)
+ if (xen_state.pgtbl_end)
return GRUB_ERR_NONE;
+ map = xen_state.mappings + xen_state.n_mappings;
+ xen_state.map_reloc = map + 1;
+
xen_state.next_start.pt_base =
xen_state.max_addr + xen_state.xen_inf.virt_base;
- xen_state.state.paging_start = xen_state.max_addr >> PAGE_SHIFT;
-
nr_info_pages = xen_state.max_addr >> PAGE_SHIFT;
- nr_pages = nr_info_pages;
+ nr_need_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_state.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)
+ try_virt_end = ALIGN_UP (xen_state.xen_inf.virt_base +
+ page2offset (nr_need_pages) +
+ ADDITIONAL_SIZE + STACK_SIZE, ALIGN_SIZE);
+ if (!xen_state.xen_inf.virt_base)
+ try_virt_end += PAGE_SIZE;
+
+ err = get_pgtable_size (xen_state.xen_inf.virt_base, try_virt_end,
+ nr_info_pages);
+ if (err)
+ return err;
+ xen_state.n_mappings++;
+
+ /* Map the relocator page either at virtual 0 or after end of area. */
+ nr_need_pages = nr_info_pages + map->area.n_pt_pages;
+ if (xen_state.xen_inf.virt_base)
+ err = get_pgtable_size (0, PAGE_SIZE, nr_need_pages);
+ else
+ err = get_pgtable_size (try_virt_end - PAGE_SIZE, try_virt_end,
+ nr_need_pages);
+ if (err)
+ return err;
+ nr_need_pages += xen_state.map_reloc->area.n_pt_pages;
+
+ if (xen_state.xen_inf.virt_base + page2offset (nr_need_pages) <=
+ try_virt_end)
break;
- nr_pages = nr_need_pages;
+
+ xen_state.n_mappings--;
}
+ xen_state.n_mappings++;
+ nr_need_pages = map->area.n_pt_pages + xen_state.map_reloc->area.n_pt_pages;
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
xen_state.max_addr,
- page2offset (nr_pt_pages));
+ page2offset (nr_need_pages));
if (err)
return err;
- xen_state.virt_pgtable = get_virtual_current_address (ch);
- xen_state.pgtbl_start = xen_state.max_addr >> PAGE_SHIFT;
- xen_state.max_addr += page2offset (nr_pt_pages);
+ map->where = get_virtual_current_address (ch);
+ map->area.pfn_start = 0;
+ xen_state.max_addr += page2offset (nr_need_pages);
xen_state.state.stack =
xen_state.max_addr + STACK_SIZE + xen_state.xen_inf.virt_base;
- xen_state.state.paging_size = nr_pt_pages;
- xen_state.next_start.nr_pt_frames = nr_pt_pages;
- xen_state.max_addr = page2offset (nr_pages);
- xen_state.pgtbl_end = nr_pages;
+ xen_state.next_start.nr_pt_frames = nr_need_pages;
+ xen_state.max_addr = try_virt_end - xen_state.xen_inf.virt_base;
+ xen_state.pgtbl_end = xen_state.max_addr >> PAGE_SHIFT;
+ xen_state.map_reloc->where = (grub_uint64_t *) ((char *) map->where +
+ page2offset (map->area.n_pt_pages));
return GRUB_ERR_NONE;
}
@@ -372,9 +486,8 @@ grub_xen_boot (void)
(unsigned long long) xen_state.xen_inf.virt_base,
(unsigned long long) page2offset (nr_pages));
- generate_page_table (xen_state.virt_pgtable, xen_state.pgtbl_start,
- xen_state.pgtbl_end, nr_pages,
- xen_state.xen_inf.virt_base, xen_state.virt_mfn_list);
+ xen_state.map_reloc->area.pfn_start = nr_pages;
+ generate_page_table (xen_state.virt_mfn_list);
xen_state.state.entry_point = xen_state.xen_inf.entry_point;
diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h
index c9b1328..8bb6e1c 100644
--- a/include/grub/i386/memory.h
+++ b/include/grub/i386/memory.h
@@ -20,6 +20,8 @@
#ifndef GRUB_MEMORY_CPU_HEADER
#define GRUB_MEMORY_CPU_HEADER 1
+#define PAGE_SHIFT 12
+
/* The flag for protected mode. */
#define GRUB_MEMORY_CPU_CR0_PE_ON 0x1
#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000020
@@ -31,6 +33,11 @@
#define GRUB_MEMORY_MACHINE_UPPER_START 0x100000 /* 1 MiB */
#define GRUB_MEMORY_MACHINE_LOWER_SIZE GRUB_MEMORY_MACHINE_UPPER_START
+/* Some PTE definitions. */
+#define GRUB_PAGE_PRESENT 0x00000001
+#define GRUB_PAGE_RW 0x00000002
+#define GRUB_PAGE_USER 0x00000004
+
#ifndef ASM_FILE
#define GRUB_MMAP_MALLOC_LOW 1
diff --git a/include/grub/xen/relocator.h b/include/grub/xen/relocator.h
index ae45dce..35a0ad9 100644
--- a/include/grub/xen/relocator.h
+++ b/include/grub/xen/relocator.h
@@ -23,11 +23,13 @@
#include <grub/err.h>
#include <grub/relocator.h>
+#define XEN_MAX_MAPPINGS 3
+
struct grub_relocator_xen_state
{
grub_addr_t start_info;
- grub_addr_t paging_start;
- grub_addr_t paging_size;
+ grub_addr_t paging_start[XEN_MAX_MAPPINGS];
+ grub_addr_t paging_size[XEN_MAX_MAPPINGS];
grub_addr_t mfn_list;
grub_addr_t stack;
grub_addr_t entry_point;
--
2.6.6

View File

@ -0,0 +1,149 @@
From e776ceae4d7fe4ba66484bec7f85110f737168f9 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 3 Mar 2016 10:38:16 +0100
Subject: [PATCH 11/11] xen: add capability to load p2m list outside of kernel
mapping
Modern pvops linux kernels support a p2m list not covered by the
kernel mapping. This capability is flagged by an elf-note specifying
the virtual address the kernel is expecting the p2m list to be mapped
to.
In case the elf-note is set by the kernel don't place the p2m list
into the kernel mapping, but map it to the given address. This will
allow to support domains with larger memory, as the kernel mapping is
limited to 2GB and a domain with huge memory in the TB range will have
a p2m list larger than this.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/loader/i386/xen.c | 53 +++++++++++++++++++++++++++++++-------
grub-core/loader/i386/xen_fileXX.c | 4 +++
include/grub/xen_file.h | 2 ++
3 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index a98badf..51d1ddd 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -313,24 +313,50 @@ static grub_err_t
grub_xen_p2m_alloc (void)
{
grub_relocator_chunk_t ch;
- grub_size_t p2msize;
+ grub_size_t p2msize, p2malloc;
grub_err_t err;
+ struct grub_xen_mapping *map;
if (xen_state.virt_mfn_list)
return GRUB_ERR_NONE;
+ map = xen_state.mappings + xen_state.n_mappings;
+ p2msize = ALIGN_UP (sizeof (grub_xen_mfn_t) *
+ grub_xen_start_page_addr->nr_pages, PAGE_SIZE);
+ if (xen_state.xen_inf.has_p2m_base)
+ {
+ err = get_pgtable_size (xen_state.xen_inf.p2m_base,
+ xen_state.xen_inf.p2m_base + p2msize,
+ (xen_state.max_addr + p2msize) >> PAGE_SHIFT);
+ if (err)
+ return err;
+
+ map->area.pfn_start = xen_state.max_addr >> PAGE_SHIFT;
+ p2malloc = p2msize + page2offset (map->area.n_pt_pages);
+ xen_state.n_mappings++;
+ xen_state.next_start.mfn_list = xen_state.xen_inf.p2m_base;
+ xen_state.next_start.first_p2m_pfn = map->area.pfn_start;
+ xen_state.next_start.nr_p2m_frames = p2malloc >> PAGE_SHIFT;
+ }
+ else
+ {
+ xen_state.next_start.mfn_list =
+ xen_state.max_addr + xen_state.xen_inf.virt_base;
+ p2malloc = p2msize;
+ }
+
xen_state.state.mfn_list = xen_state.max_addr;
- xen_state.next_start.mfn_list =
- xen_state.max_addr + xen_state.xen_inf.virt_base;
- p2msize = sizeof (grub_xen_mfn_t) * grub_xen_start_page_addr->nr_pages;
err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
- xen_state.max_addr, p2msize);
+ xen_state.max_addr, p2malloc);
if (err)
return err;
xen_state.virt_mfn_list = get_virtual_current_address (ch);
+ if (xen_state.xen_inf.has_p2m_base)
+ map->where = (grub_uint64_t *) xen_state.virt_mfn_list +
+ p2msize / sizeof (grub_uint64_t);
grub_memcpy (xen_state.virt_mfn_list,
(void *) grub_xen_start_page_addr->mfn_list, p2msize);
- xen_state.max_addr = ALIGN_UP (xen_state.max_addr + p2msize, PAGE_SIZE);
+ xen_state.max_addr += p2malloc;
return GRUB_ERR_NONE;
}
@@ -448,9 +474,12 @@ grub_xen_alloc_boot_data (void)
{
grub_err_t err;
- err = grub_xen_p2m_alloc ();
- if (err)
- return err;
+ if (!xen_state.xen_inf.has_p2m_base)
+ {
+ err = grub_xen_p2m_alloc ();
+ if (err)
+ return err;
+ }
err = grub_xen_special_alloc ();
if (err)
return err;
@@ -475,6 +504,12 @@ grub_xen_boot (void)
err = grub_xen_alloc_boot_data ();
if (err)
return err;
+ if (xen_state.xen_inf.has_p2m_base)
+ {
+ err = grub_xen_p2m_alloc ();
+ if (err)
+ return err;
+ }
err = set_mfns (xen_state.console_pfn);
if (err)
diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
index 8751174..fb66e66 100644
--- a/grub-core/loader/i386/xen_fileXX.c
+++ b/grub-core/loader/i386/xen_fileXX.c
@@ -261,6 +261,10 @@ parse_note (grub_elf_t elf, struct grub_xen_file_info *xi,
descsz == 2 ? 2 : 3) == 0)
xi->arch = GRUB_XEN_FILE_I386;
break;
+ case XEN_ELFNOTE_INIT_P2M:
+ xi->p2m_base = grub_le_to_cpu_addr (*(Elf_Addr *) desc);
+ xi->has_p2m_base = 1;
+ break;
case XEN_ELFNOTE_MOD_START_PFN:
xi->unmapped_initrd = !!grub_le_to_cpu32(*(grub_uint32_t *) desc);
break;
diff --git a/include/grub/xen_file.h b/include/grub/xen_file.h
index ed749fa..6587999 100644
--- a/include/grub/xen_file.h
+++ b/include/grub/xen_file.h
@@ -32,9 +32,11 @@ struct grub_xen_file_info
grub_uint64_t entry_point;
grub_uint64_t hypercall_page;
grub_uint64_t paddr_offset;
+ grub_uint64_t p2m_base;
int has_hypercall_page;
int has_note;
int has_xen_guest;
+ int has_p2m_base;
int extended_cr3;
int unmapped_initrd;
enum
--
2.6.6

View File

@ -1,3 +1,20 @@
-------------------------------------------------------------------
Fri Oct 21 09:34:58 UTC 2016 - mchang@suse.com
- From Juergen Gross <jgross@suse.com>: grub-xen: support booting huge
pv-domains (bsc#1004398) (bsc#899465)
* 0001-xen-make-xen-loader-callable-multiple-times.patch
* 0002-xen-avoid-memleaks-on-error.patch
* 0003-xen-reduce-number-of-global-variables-in-xen-loader.patch
* 0004-xen-add-elfnote.h-to-avoid-using-numbers-instead-of-.patch
* 0005-xen-synchronize-xen-header.patch
* 0006-xen-factor-out-p2m-list-allocation-into-separate-fun.patch
* 0007-xen-factor-out-allocation-of-special-pages-into-sepa.patch
* 0008-xen-factor-out-allocation-of-page-tables-into-separa.patch
* 0009-xen-add-capability-to-load-initrd-outside-of-initial.patch
* 0010-xen-modify-page-table-construction.patch
* 0011-xen-add-capability-to-load-p2m-list-outside-of-kerne.patch
-------------------------------------------------------------------
Tue Oct 11 20:59:40 UTC 2016 - dmueller@suse.com

View File

@ -230,6 +230,18 @@ Patch284: 0005-grub.texi-Add-net_bootp6-doument.patch
Patch285: 0006-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
Patch286: 0007-efinet-Setting-network-from-UEFI-device-path.patch
Patch287: 0008-efinet-Setting-DNS-server-from-UEFI-protocol.patch
# Support booting huge xen pv-domains (bsc#1004398) (bsc#899465)
Patch300: 0001-xen-make-xen-loader-callable-multiple-times.patch
Patch301: 0002-xen-avoid-memleaks-on-error.patch
Patch302: 0003-xen-reduce-number-of-global-variables-in-xen-loader.patch
Patch303: 0004-xen-add-elfnote.h-to-avoid-using-numbers-instead-of-.patch
Patch304: 0005-xen-synchronize-xen-header.patch
Patch305: 0006-xen-factor-out-p2m-list-allocation-into-separate-fun.patch
Patch306: 0007-xen-factor-out-allocation-of-special-pages-into-sepa.patch
Patch307: 0008-xen-factor-out-allocation-of-page-tables-into-separa.patch
Patch308: 0009-xen-add-capability-to-load-initrd-outside-of-initial.patch
Patch309: 0010-xen-modify-page-table-construction.patch
Patch310: 0011-xen-add-capability-to-load-p2m-list-outside-of-kerne.patch
Requires: gettext-runtime
%if 0%{?suse_version} >= 1140
@ -463,6 +475,17 @@ swap partition while in resuming
%patch285 -p1
%patch286 -p1
%patch287 -p1
%patch300 -p1
%patch301 -p1
%patch302 -p1
%patch303 -p1
%patch304 -p1
%patch305 -p1
%patch306 -p1
%patch307 -p1
%patch308 -p1
%patch309 -p1
%patch310 -p1
# This simplifies patch handling without need to use git to create patch
# that renames file