xref: /linux/arch/x86/kernel/relocate_kernel_64.S (revision ee665ecca6d6775f65b1a4154c34f551f62cec52)
1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
4 *
5 * This source code is licensed under the GNU General Public License,
6 * Version 2.  See the file COPYING for more details.
7 */
8
9#include <linux/linkage.h>
10#include <asm/page_types.h>
11#include <asm/kexec.h>
12#include <asm/processor-flags.h>
13#include <asm/pgtable_types.h>
14
15/*
16 * Must be relocatable PIC code callable as a C function
17 */
18
19#define PTR(x) (x << 3)
20#define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
21
22	.text
23	.align PAGE_SIZE
24	.code64
25	.globl relocate_kernel
26relocate_kernel:
27	/* %rdi indirection_page
28	 * %rsi page_list
29	 * %rdx start address
30	 */
31
32	/* zero out flags, and disable interrupts */
33	pushq $0
34	popfq
35
36	/* get physical address of control page now */
37	/* this is impossible after page table switch */
38	movq	PTR(PA_CONTROL_PAGE)(%rsi), %r8
39
40	/* get physical address of page table now too */
41	movq	PTR(PA_TABLE_PAGE)(%rsi), %rcx
42
43	/* Switch to the identity mapped page tables */
44	movq	%rcx, %cr3
45
46	/* setup a new stack at the end of the physical control page */
47	lea	PAGE_SIZE(%r8), %rsp
48
49	/* jump to identity mapped page */
50	addq	$(identity_mapped - relocate_kernel), %r8
51	pushq	%r8
52	ret
53
54identity_mapped:
55	/* store the start address on the stack */
56	pushq   %rdx
57
58	/* Set cr0 to a known state:
59	 *  - Paging enabled
60	 *  - Alignment check disabled
61	 *  - Write protect disabled
62	 *  - No task switch
63	 *  - Don't do FP software emulation.
64	 *  - Proctected mode enabled
65	 */
66	movq	%cr0, %rax
67	andq	$~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %rax
68	orl	$(X86_CR0_PG | X86_CR0_PE), %eax
69	movq	%rax, %cr0
70
71	/* Set cr4 to a known state:
72	 *  - physical address extension enabled
73	 */
74	movq	$X86_CR4_PAE, %rax
75	movq	%rax, %cr4
76
77	jmp 1f
781:
79
80	/* Flush the TLB (needed?) */
81	movq	%rcx, %cr3
82
83	/* Do the copies */
84	movq	%rdi, %rcx 	/* Put the page_list in %rcx */
85	xorq	%rdi, %rdi
86	xorq	%rsi, %rsi
87	jmp	1f
88
890:	/* top, read another word for the indirection page */
90
91	movq	(%rbx), %rcx
92	addq	$8,	%rbx
931:
94	testq	$0x1,	%rcx  /* is it a destination page? */
95	jz	2f
96	movq	%rcx,	%rdi
97	andq	$0xfffffffffffff000, %rdi
98	jmp	0b
992:
100	testq	$0x2,	%rcx  /* is it an indirection page? */
101	jz	2f
102	movq	%rcx,   %rbx
103	andq	$0xfffffffffffff000, %rbx
104	jmp	0b
1052:
106	testq	$0x4,	%rcx  /* is it the done indicator? */
107	jz	2f
108	jmp	3f
1092:
110	testq	$0x8,	%rcx  /* is it the source indicator? */
111	jz	0b	      /* Ignore it otherwise */
112	movq	%rcx,   %rsi  /* For ever source page do a copy */
113	andq	$0xfffffffffffff000, %rsi
114
115	movq	$512,   %rcx
116	rep ; movsq
117	jmp	0b
1183:
119
120	/* To be certain of avoiding problems with self-modifying code
121	 * I need to execute a serializing instruction here.
122	 * So I flush the TLB by reloading %cr3 here, it's handy,
123	 * and not processor dependent.
124	 */
125	movq	%cr3, %rax
126	movq	%rax, %cr3
127
128	/* set all of the registers to known values */
129	/* leave %rsp alone */
130
131	xorq	%rax, %rax
132	xorq	%rbx, %rbx
133	xorq    %rcx, %rcx
134	xorq    %rdx, %rdx
135	xorq    %rsi, %rsi
136	xorq    %rdi, %rdi
137	xorq    %rbp, %rbp
138	xorq	%r8,  %r8
139	xorq	%r9,  %r9
140	xorq	%r10, %r9
141	xorq	%r11, %r11
142	xorq	%r12, %r12
143	xorq	%r13, %r13
144	xorq	%r14, %r14
145	xorq	%r15, %r15
146
147	ret
148