summaryrefslogtreecommitdiffstats
path: root/grub-core/lib/x86_64/xen/relocator.S
blob: f5364ed0f4c8e8f85be6cc0d88c60deed2ab20c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2013  Free Software Foundation, Inc.
 *
 *  GRUB is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/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):
	/* Remap the remapper to it's new address. */
	MOV_IMM64_RAX(grub_relocator_xen_remapper_virt)

	movq    %rax, %rdi	/* %rdi: new virtual address of remapper */
	movq    %rax, %rbx	/* Remember new virtual address */

	MOV_IMM64_RAX(grub_relocator_xen_remapper_map)

	movq    %rax, %rsi	/* %rsi: page table entry */

	movq    $UVMF_INVLPG, %rdx	/* %rdx: flags (inv. single entry) */
	movq    $__HYPERVISOR_update_va_mapping, %rax
	syscall			/* Do the remap operation */

	addq   $(LOCAL(cont) - LOCAL(base)), %rbx

	jmp *%rbx		/* Continue with new virtual address */

LOCAL(cont):
	/* 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

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
	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
	incq	%r12		/* next pfn */

	loop 2b

	addq	$(2 * GRUB_TARGET_SIZEOF_LONG), %r8	/* next pg table area */
	jmp	1b

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

	/* Continue in virtual kernel mapping. */
	MOV_IMM64_RAX(grub_relocator_xen_remap_continue)

	jmp *%rax

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

VARIABLE(grub_relocator_xen_remap_end)


VARIABLE(grub_relocator_xen_start)
	/* Unmap old remapper area. */
	MOV_IMM64_RAX(grub_relocator_xen_remapper_virt2)

	movq    %rax, %rdi

	xorq    %rax, %rax	/* Invalid pte */
	movq    %rax, %rsi

	movq    $UVMF_INVLPG, %rdx
	movq    $__HYPERVISOR_update_va_mapping, %rax
	syscall

	/* Prepare registers for starting kernel. */
	MOV_IMM64_RAX(grub_relocator_xen_stack)

	movq	%rax, %rsp

	MOV_IMM64_RAX(grub_relocator_xen_start_info)

	movq	%rax, %rsi

	cld

	MOV_IMM64_RAX(grub_relocator_xen_entry_point)

	/* Now start the new kernel. */
	jmp *%rax

VARIABLE(grub_relocator_xen_end)