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