forked from pool/grub2
8da1cb3353
- 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
952 lines
28 KiB
Diff
952 lines
28 KiB
Diff
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
|
|
|